mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 19:54:44 -07:00
allow users to launch with support for multiple GPUs, image gen UI bug fixes, adding the new 1.98.0 sdflashattention and sdconvdirect image gen options, remove cspell
This commit is contained in:
parent
8c6f3a308d
commit
2ef23888df
26 changed files with 509 additions and 1391 deletions
|
|
@ -1,102 +0,0 @@
|
||||||
alsa
|
|
||||||
AMDGPU
|
|
||||||
ansi
|
|
||||||
ANSI
|
|
||||||
APPIMAGE
|
|
||||||
stripansi
|
|
||||||
asar
|
|
||||||
Autoencoder
|
|
||||||
BLAS
|
|
||||||
clblast
|
|
||||||
clinfo
|
|
||||||
Consolas
|
|
||||||
contextsize
|
|
||||||
Cooldown
|
|
||||||
cublas
|
|
||||||
cuda
|
|
||||||
CUDA
|
|
||||||
Dolfino
|
|
||||||
finetuned
|
|
||||||
flashattention
|
|
||||||
Flashattention
|
|
||||||
friendlykobold
|
|
||||||
geforce
|
|
||||||
ggml
|
|
||||||
gguf
|
|
||||||
GGUF
|
|
||||||
gpulayers
|
|
||||||
hipblas
|
|
||||||
kcpps
|
|
||||||
kcppt
|
|
||||||
koboldai
|
|
||||||
KOBOLDAI
|
|
||||||
koboldcpp
|
|
||||||
KoboldCpp
|
|
||||||
KOBOLDCPP
|
|
||||||
libxss
|
|
||||||
lora
|
|
||||||
lowvram
|
|
||||||
Lowvram
|
|
||||||
makepkg
|
|
||||||
maximizable
|
|
||||||
minimizable
|
|
||||||
MMAP
|
|
||||||
mmproj
|
|
||||||
mmq
|
|
||||||
multiuser
|
|
||||||
noavx
|
|
||||||
nocertify
|
|
||||||
nocuda
|
|
||||||
noheader
|
|
||||||
nommq
|
|
||||||
noshift
|
|
||||||
nsis
|
|
||||||
nvidia
|
|
||||||
oldpc
|
|
||||||
OLDPC
|
|
||||||
opencl
|
|
||||||
optdepends
|
|
||||||
paru
|
|
||||||
pkexec
|
|
||||||
pkgbase
|
|
||||||
PKGBUILD
|
|
||||||
pkgdesc
|
|
||||||
pkgdir
|
|
||||||
pkgname
|
|
||||||
pkgrel
|
|
||||||
pkgver
|
|
||||||
quantmatmul
|
|
||||||
radeon
|
|
||||||
remotetunnel
|
|
||||||
rocm
|
|
||||||
ROCM
|
|
||||||
rocminfo
|
|
||||||
safetensors
|
|
||||||
sdclipg
|
|
||||||
sdclipl
|
|
||||||
sdlora
|
|
||||||
sdmodel
|
|
||||||
sdphotomaker
|
|
||||||
sdui
|
|
||||||
sdvae
|
|
||||||
SDXL
|
|
||||||
Segoe
|
|
||||||
sonarjs
|
|
||||||
SPACEBAR
|
|
||||||
squashfs
|
|
||||||
SRCINFO
|
|
||||||
taskkill
|
|
||||||
Tauri
|
|
||||||
togglefullscreen
|
|
||||||
treemap
|
|
||||||
trycloudflare
|
|
||||||
unquantized
|
|
||||||
useclblast
|
|
||||||
usecuda
|
|
||||||
usemmap
|
|
||||||
usevulkan
|
|
||||||
vram
|
|
||||||
vulkan
|
|
||||||
vulkaninfo
|
|
||||||
wayland
|
|
||||||
websearch
|
|
||||||
6
.vscode/extensions.json
vendored
6
.vscode/extensions.json
vendored
|
|
@ -1,7 +1,3 @@
|
||||||
{
|
{
|
||||||
"recommendations": [
|
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"streetsidesoftware.code-spell-checker"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
.vscode/tasks.json
vendored
14
.vscode/tasks.json
vendored
|
|
@ -46,19 +46,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Spell Check",
|
"label": "Check All (Lint + Type)",
|
||||||
"type": "shell",
|
|
||||||
"command": "yarn spell-check",
|
|
||||||
"group": "test",
|
|
||||||
"presentation": {
|
|
||||||
"echo": true,
|
|
||||||
"reveal": "always",
|
|
||||||
"focus": false,
|
|
||||||
"panel": "shared"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Check All (Lint + Type + Spell)",
|
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "yarn check-all",
|
"command": "yarn check-all",
|
||||||
"group": "test",
|
"group": "test",
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ A desktop app for running Large Language Models locally. <!-- markdownlint-disab
|
||||||
|
|
||||||
Download the latest release for your platform from the [GitHub Releases page](https://github.com/lone-cloud/friendly-kobold/releases/latest):
|
Download the latest release for your platform from the [GitHub Releases page](https://github.com/lone-cloud/friendly-kobold/releases/latest):
|
||||||
|
|
||||||
- **Windows**: `Friendly.Kobold.Portable X.X.X.exe` (portable executable)
|
- **Windows**: `Friendly.Kobold-Portable-X.X.X.exe` (portable executable)
|
||||||
- **Windows**: `Friendly.Kobold.Setup X.X.X.exe` (installer executable)
|
- **Windows**: `Friendly.Kobold-Setup-X.X.X.exe` (installer executable)
|
||||||
- **macOS**: `Friendly.Kobold-X.X.X.dmg` (disk image)
|
- **macOS**: `Friendly.Kobold-X.X.X.dmg` (disk image)
|
||||||
- **Linux**: `Friendly.Kobold-X.X.X.AppImage` (portable application)
|
- **Linux**: `Friendly.Kobold-X.X.X.AppImage` (portable application)
|
||||||
|
|
||||||
|
|
|
||||||
66
cspell.json
66
cspell.json
|
|
@ -1,66 +0,0 @@
|
||||||
{
|
|
||||||
"version": "0.2",
|
|
||||||
"language": "en",
|
|
||||||
"dictionaryDefinitions": [
|
|
||||||
{
|
|
||||||
"name": "project-terms",
|
|
||||||
"path": "./.cspell/project-terms.txt",
|
|
||||||
"addWords": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"dictionaries": [
|
|
||||||
"typescript",
|
|
||||||
"node",
|
|
||||||
"npm",
|
|
||||||
"html",
|
|
||||||
"css",
|
|
||||||
"bash",
|
|
||||||
"en-gb",
|
|
||||||
"companies",
|
|
||||||
"softwareTerms",
|
|
||||||
"misc",
|
|
||||||
"project-terms"
|
|
||||||
],
|
|
||||||
"ignorePaths": [
|
|
||||||
"node_modules/**",
|
|
||||||
"dist/**",
|
|
||||||
"dist-electron/**",
|
|
||||||
"out/**",
|
|
||||||
"release/**",
|
|
||||||
"build/**",
|
|
||||||
"*.min.js",
|
|
||||||
"*.min.css",
|
|
||||||
"package-lock.json",
|
|
||||||
"**/*.log",
|
|
||||||
"coverage/**",
|
|
||||||
".git/**",
|
|
||||||
".vscode/**",
|
|
||||||
"*.map",
|
|
||||||
".cspell/**"
|
|
||||||
],
|
|
||||||
"languageSettings": [
|
|
||||||
{
|
|
||||||
"languageId": "typescript,javascript",
|
|
||||||
"caseSensitive": true,
|
|
||||||
"dictionaries": ["typescript", "node", "npm", "softwareTerms"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"languageId": "css,scss,less",
|
|
||||||
"dictionaries": ["css", "fonts"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"languageId": "html",
|
|
||||||
"dictionaries": ["html", "css", "typescript"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"filename": "**/*.md",
|
|
||||||
"dictionaries": ["en-gb", "typescript", "node", "npm", "companies"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "**/README.md",
|
|
||||||
"words": ["github", "screenshot", "screenshots", "workflow", "workflows"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,6 @@ import reactRefresh from 'eslint-plugin-react-refresh';
|
||||||
import react from 'eslint-plugin-react';
|
import react from 'eslint-plugin-react';
|
||||||
import importPlugin from 'eslint-plugin-import';
|
import importPlugin from 'eslint-plugin-import';
|
||||||
import sonarjs from 'eslint-plugin-sonarjs';
|
import sonarjs from 'eslint-plugin-sonarjs';
|
||||||
import cspell from '@cspell/eslint-plugin';
|
|
||||||
import noComments from 'eslint-plugin-no-comments';
|
import noComments from 'eslint-plugin-no-comments';
|
||||||
|
|
||||||
const config = [
|
const config = [
|
||||||
|
|
@ -47,7 +46,6 @@ const config = [
|
||||||
react: react,
|
react: react,
|
||||||
import: importPlugin,
|
import: importPlugin,
|
||||||
sonarjs: sonarjs,
|
sonarjs: sonarjs,
|
||||||
'@cspell': cspell,
|
|
||||||
'no-comments': noComments,
|
'no-comments': noComments,
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
|
|
@ -116,8 +114,6 @@ const config = [
|
||||||
|
|
||||||
'sonarjs/cognitive-complexity': ['warn', 25],
|
'sonarjs/cognitive-complexity': ['warn', 25],
|
||||||
|
|
||||||
'@cspell/spellchecker': ['warn'],
|
|
||||||
|
|
||||||
'no-comments/disallowComments': 'error',
|
'no-comments/disallowComments': 'error',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
24
package.json
24
package.json
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "friendly-kobold",
|
"name": "friendly-kobold",
|
||||||
"productName": "Friendly Kobold",
|
"productName": "Friendly Kobold",
|
||||||
"version": "0.7.0",
|
"version": "0.8.0",
|
||||||
"description": "A desktop app for running Large Language Models locally",
|
"description": "A desktop app for running Large Language Models locally",
|
||||||
"main": "out/main/index.js",
|
"main": "out/main/index.js",
|
||||||
"homepage": "./",
|
"homepage": "./",
|
||||||
|
|
@ -23,20 +23,16 @@
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "eslint . --fix",
|
||||||
"compile": "tsc --noEmit",
|
"compile": "tsc --noEmit",
|
||||||
"spell-check": "cspell \"**/*.{ts,tsx,js,jsx,md,json}\" --no-progress",
|
"check-all": "yarn lint && yarn compile",
|
||||||
"spell-check:fix": "cspell \"**/*.{ts,tsx,js,jsx,md,json}\" --no-progress --show-suggestions",
|
|
||||||
"check-all": "yarn lint && yarn compile && yarn spell-check",
|
|
||||||
"release": "yarn dlx tsx scripts/release.ts",
|
"release": "yarn dlx tsx scripts/release.ts",
|
||||||
"prepare": "husky"
|
"prepare": "husky"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js,jsx,ts,tsx}": [
|
"*.{js,jsx,ts,tsx}": [
|
||||||
"eslint --fix",
|
"eslint --fix",
|
||||||
"cspell \"**/*.{ts,tsx,js,jsx,md,json}\" --no-progress",
|
|
||||||
"prettier --write --ignore-path .gitignore"
|
"prettier --write --ignore-path .gitignore"
|
||||||
],
|
],
|
||||||
"*.{json,css,md}": [
|
"*.{json,css,md}": [
|
||||||
"cspell \"**/*.{ts,tsx,js,jsx,md,json}\" --no-progress",
|
|
||||||
"prettier --write --ignore-path .gitignore"
|
"prettier --write --ignore-path .gitignore"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -56,17 +52,15 @@
|
||||||
},
|
},
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@cspell/eslint-plugin": "^9.2.0",
|
|
||||||
"@eslint/js": "^9.34.0",
|
"@eslint/js": "^9.34.0",
|
||||||
"@types/node": "^24.3.0",
|
"@types/node": "^24.3.0",
|
||||||
"@types/react": "^19.1.11",
|
"@types/react": "^19.1.11",
|
||||||
"@types/react-dom": "^19.1.7",
|
"@types/react-dom": "^19.1.7",
|
||||||
"@types/strip-ansi": "^5.2.1",
|
"@types/strip-ansi": "^5.2.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.40.0",
|
"@typescript-eslint/eslint-plugin": "^8.41.0",
|
||||||
"@typescript-eslint/parser": "^8.40.0",
|
"@typescript-eslint/parser": "^8.41.0",
|
||||||
"@vitejs/plugin-react": "^5.0.1",
|
"@vitejs/plugin-react": "^5.0.1",
|
||||||
"cross-env": "^10.0.0",
|
"cross-env": "^10.0.0",
|
||||||
"cspell": "^9.2.0",
|
|
||||||
"electron": "^37.3.1",
|
"electron": "^37.3.1",
|
||||||
"electron-builder": "^26.0.12",
|
"electron-builder": "^26.0.12",
|
||||||
"electron-vite": "^4.0.0",
|
"electron-vite": "^4.0.0",
|
||||||
|
|
@ -76,7 +70,7 @@
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.20",
|
"eslint-plugin-react-refresh": "^0.4.20",
|
||||||
"eslint-plugin-sonarjs": "^3.0.4",
|
"eslint-plugin-sonarjs": "^3.0.5",
|
||||||
"globals": "^16.3.0",
|
"globals": "^16.3.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"jiti": "^2.5.1",
|
"jiti": "^2.5.1",
|
||||||
|
|
@ -95,7 +89,7 @@
|
||||||
"react": "^19.1.1",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^19.1.1",
|
"react-dom": "^19.1.1",
|
||||||
"strip-ansi": "^7.1.0",
|
"strip-ansi": "^7.1.0",
|
||||||
"systeminformation": "^5.27.7",
|
"systeminformation": "^5.27.8",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0",
|
"winston-daily-rotate-file": "^5.0.0",
|
||||||
"zustand": "^5.0.8"
|
"zustand": "^5.0.8"
|
||||||
|
|
@ -168,7 +162,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"nsis": {
|
"nsis": {
|
||||||
"artifactName": "${productName} Setup ${version}.${ext}",
|
"artifactName": "${productName}-Setup-${version}.${ext}",
|
||||||
"oneClick": false,
|
"oneClick": false,
|
||||||
"allowToChangeInstallationDirectory": true,
|
"allowToChangeInstallationDirectory": true,
|
||||||
"createDesktopShortcut": true,
|
"createDesktopShortcut": true,
|
||||||
|
|
@ -176,11 +170,11 @@
|
||||||
"shortcutName": "Friendly Kobold"
|
"shortcutName": "Friendly Kobold"
|
||||||
},
|
},
|
||||||
"portable": {
|
"portable": {
|
||||||
"artifactName": "${productName} Portable ${version}.${ext}"
|
"artifactName": "${productName}-Portable-${version}.${ext}"
|
||||||
},
|
},
|
||||||
"linux": {
|
"linux": {
|
||||||
"compression": "store",
|
"compression": "store",
|
||||||
"category": "Development",
|
"category": "Utility",
|
||||||
"desktop": {
|
"desktop": {
|
||||||
"entry": {
|
"entry": {
|
||||||
"Name": "Friendly Kobold",
|
"Name": "Friendly Kobold",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import { useUpdateChecker } from '@/hooks/useUpdateChecker';
|
||||||
import { useKoboldVersions } from '@/hooks/useKoboldVersions';
|
import { useKoboldVersions } from '@/hooks/useKoboldVersions';
|
||||||
import { UI } from '@/constants';
|
import { UI } from '@/constants';
|
||||||
import type { DownloadItem } from '@/types/electron';
|
import type { DownloadItem } from '@/types/electron';
|
||||||
|
import type { InterfaceTab } from '@/types';
|
||||||
|
|
||||||
type Screen = 'welcome' | 'download' | 'launch' | 'interface';
|
type Screen = 'welcome' | 'download' | 'launch' | 'interface';
|
||||||
|
|
||||||
|
|
@ -21,11 +22,9 @@ export const App = () => {
|
||||||
const [settingsOpened, setSettingsOpened] = useState(false);
|
const [settingsOpened, setSettingsOpened] = useState(false);
|
||||||
const [hasInitialized, setHasInitialized] = useState(false);
|
const [hasInitialized, setHasInitialized] = useState(false);
|
||||||
const [showEjectModal, setShowEjectModal] = useState(false);
|
const [showEjectModal, setShowEjectModal] = useState(false);
|
||||||
const [activeInterfaceTab, setActiveInterfaceTab] = useState<string | null>(
|
const [activeInterfaceTab, setActiveInterfaceTab] =
|
||||||
'terminal'
|
useState<InterfaceTab>('terminal');
|
||||||
);
|
const [isImageGenerationMode, setIsImageGenerationMode] = useState(false);
|
||||||
const [isImageGenerationMode, setIsImageGenerationMode] =
|
|
||||||
useState<boolean>(false);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
updateInfo: binaryUpdateInfo,
|
updateInfo: binaryUpdateInfo,
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,15 @@ import {
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { Settings, ArrowLeft } from 'lucide-react';
|
import { Settings, ArrowLeft } from 'lucide-react';
|
||||||
import { soundAssets, playSound, initializeAudio } from '@/utils';
|
import { soundAssets, playSound, initializeAudio } from '@/utils';
|
||||||
|
import type { InterfaceTab } from '@/types';
|
||||||
import iconUrl from '/icon.png';
|
import iconUrl from '/icon.png';
|
||||||
|
|
||||||
type Screen = 'welcome' | 'download' | 'launch' | 'interface';
|
type Screen = 'welcome' | 'download' | 'launch' | 'interface';
|
||||||
|
|
||||||
interface AppHeaderProps {
|
interface AppHeaderProps {
|
||||||
currentScreen: Screen | null;
|
currentScreen: Screen | null;
|
||||||
activeInterfaceTab: string | null;
|
activeInterfaceTab: InterfaceTab;
|
||||||
setActiveInterfaceTab: (tab: string | null) => void;
|
setActiveInterfaceTab: (tab: InterfaceTab) => void;
|
||||||
isImageGenerationMode: boolean;
|
isImageGenerationMode: boolean;
|
||||||
onEject: () => void;
|
onEject: () => void;
|
||||||
onSettingsOpen: () => void;
|
onSettingsOpen: () => void;
|
||||||
|
|
@ -109,8 +110,10 @@ export const AppHeader = ({
|
||||||
|
|
||||||
{currentScreen === 'interface' && (
|
{currentScreen === 'interface' && (
|
||||||
<Select
|
<Select
|
||||||
value={activeInterfaceTab || 'terminal'}
|
value={activeInterfaceTab}
|
||||||
onChange={(value) => setActiveInterfaceTab(value || 'terminal')}
|
onChange={(value) =>
|
||||||
|
setActiveInterfaceTab((value || 'terminal') as InterfaceTab)
|
||||||
|
}
|
||||||
data={[
|
data={[
|
||||||
{
|
{
|
||||||
value: 'chat',
|
value: 'chat',
|
||||||
|
|
|
||||||
23
src/components/LabelWithTooltip.tsx
Normal file
23
src/components/LabelWithTooltip.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { Group, Text } from '@mantine/core';
|
||||||
|
import { InfoTooltip } from '@/components/InfoTooltip';
|
||||||
|
|
||||||
|
interface LabelWithTooltipProps {
|
||||||
|
label: string;
|
||||||
|
tooltip?: string;
|
||||||
|
fontWeight?: number;
|
||||||
|
marginBottom?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LabelWithTooltip = ({
|
||||||
|
label,
|
||||||
|
tooltip,
|
||||||
|
fontWeight = 500,
|
||||||
|
marginBottom = 'xs',
|
||||||
|
}: LabelWithTooltipProps) => (
|
||||||
|
<Group gap="xs" align="center" mb={marginBottom}>
|
||||||
|
<Text size="sm" fw={fontWeight}>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
{tooltip && <InfoTooltip label={tooltip} />}
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Group, TextInput, Button } from '@mantine/core';
|
import { Group, TextInput, Button } from '@mantine/core';
|
||||||
import { File, Search } from 'lucide-react';
|
import { File, Search } from 'lucide-react';
|
||||||
import { SectionHeader } from '@/components/SectionHeader';
|
import { LabelWithTooltip } from '@/components/LabelWithTooltip';
|
||||||
import { getInputValidationState } from '@/utils';
|
import { getInputValidationState } from '@/utils';
|
||||||
import styles from '@/styles/layout.module.css';
|
import styles from '@/styles/layout.module.css';
|
||||||
|
|
||||||
|
|
@ -39,12 +39,7 @@ export const ModelFileField = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<SectionHeader
|
<LabelWithTooltip label={label} tooltip={tooltip} />
|
||||||
title={label}
|
|
||||||
tooltip={tooltip}
|
|
||||||
fontWeight={500}
|
|
||||||
marginBottom="xs"
|
|
||||||
/>
|
|
||||||
<Group gap="xs" align="flex-start">
|
<Group gap="xs" align="flex-start">
|
||||||
<div className={styles.flex1}>
|
<div className={styles.flex1}>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
|
|
||||||
40
src/components/SelectWithTooltip.tsx
Normal file
40
src/components/SelectWithTooltip.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import type { CSSProperties } from 'react';
|
||||||
|
import { Select } from '@mantine/core';
|
||||||
|
import type { ComboboxItem } from '@mantine/core';
|
||||||
|
import { LabelWithTooltip } from '@/components/LabelWithTooltip';
|
||||||
|
|
||||||
|
interface SelectWithTooltipProps {
|
||||||
|
label: string;
|
||||||
|
tooltip: string;
|
||||||
|
value: string;
|
||||||
|
onChange: (value: string | null, option: ComboboxItem) => void;
|
||||||
|
data: { value: string; label: string }[];
|
||||||
|
placeholder?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
clearable?: boolean;
|
||||||
|
style?: CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SelectWithTooltip = ({
|
||||||
|
label,
|
||||||
|
tooltip,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
data,
|
||||||
|
placeholder,
|
||||||
|
disabled = false,
|
||||||
|
clearable = false,
|
||||||
|
style,
|
||||||
|
}: SelectWithTooltipProps) => (
|
||||||
|
<div style={style}>
|
||||||
|
<LabelWithTooltip label={label} tooltip={tooltip} />
|
||||||
|
<Select
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
data={data}
|
||||||
|
disabled={disabled}
|
||||||
|
clearable={clearable}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { Box, Text, Stack } from '@mantine/core';
|
import { Box, Text, Stack } from '@mantine/core';
|
||||||
import { UI } from '@/constants';
|
import { UI } from '@/constants';
|
||||||
|
import type { ServerTabMode } from '@/types';
|
||||||
|
|
||||||
interface ServerTabProps {
|
interface ServerTabProps {
|
||||||
serverUrl?: string;
|
serverUrl?: string;
|
||||||
isServerReady?: boolean;
|
isServerReady?: boolean;
|
||||||
mode: 'chat' | 'image-generation';
|
mode: ServerTabMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ServerTab = ({
|
export const ServerTab = ({
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback } from 'react';
|
||||||
import { ServerTab } from '@/components/screens/Interface/ServerTab';
|
import { ServerTab } from '@/components/screens/Interface/ServerTab';
|
||||||
import { TerminalTab } from '@/components/screens/Interface/TerminalTab';
|
import { TerminalTab } from '@/components/screens/Interface/TerminalTab';
|
||||||
|
import type { InterfaceTab } from '@/types';
|
||||||
|
|
||||||
interface InterfaceScreenProps {
|
interface InterfaceScreenProps {
|
||||||
activeTab?: string | null;
|
activeTab?: InterfaceTab | null;
|
||||||
onTabChange?: (tab: string | null) => void;
|
onTabChange?: (tab: InterfaceTab) => void;
|
||||||
isImageGenerationMode?: boolean;
|
isImageGenerationMode?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -21,10 +22,10 @@ export const InterfaceScreen = ({
|
||||||
setServerUrl(url);
|
setServerUrl(url);
|
||||||
setIsServerReady(true);
|
setIsServerReady(true);
|
||||||
if (onTabChange) {
|
if (onTabChange) {
|
||||||
onTabChange(isImageGenerationMode ? 'image' : 'chat');
|
onTabChange('chat');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[onTabChange, isImageGenerationMode]
|
[onTabChange]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -48,18 +49,6 @@ export const InterfaceScreen = ({
|
||||||
mode={isImageGenerationMode ? 'image-generation' : 'chat'}
|
mode={isImageGenerationMode ? 'image-generation' : 'chat'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
display: activeTab === 'image' ? 'block' : 'none',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ServerTab
|
|
||||||
serverUrl={serverUrl}
|
|
||||||
isServerReady={isServerReady}
|
|
||||||
mode="image-generation"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { Text, Group, Select, Checkbox, TextInput } from '@mantine/core';
|
||||||
import { useState, useEffect, useRef } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import { InfoTooltip } from '@/components/InfoTooltip';
|
import { InfoTooltip } from '@/components/InfoTooltip';
|
||||||
import { BackendSelectItem } from '@/components/screens/Launch/GeneralTab/BackendSelectItem';
|
import { BackendSelectItem } from '@/components/screens/Launch/GeneralTab/BackendSelectItem';
|
||||||
|
import { GpuDeviceSelector } from '@/components/screens/Launch/GeneralTab/GpuDeviceSelector';
|
||||||
import { useLaunchConfig } from '@/hooks/useLaunchConfig';
|
import { useLaunchConfig } from '@/hooks/useLaunchConfig';
|
||||||
|
|
||||||
interface BackendSelectorProps {
|
interface BackendSelectorProps {
|
||||||
|
|
@ -11,11 +12,9 @@ interface BackendSelectorProps {
|
||||||
export const BackendSelector = ({ onBackendsReady }: BackendSelectorProps) => {
|
export const BackendSelector = ({ onBackendsReady }: BackendSelectorProps) => {
|
||||||
const {
|
const {
|
||||||
backend,
|
backend,
|
||||||
gpuDevice,
|
|
||||||
gpuLayers,
|
gpuLayers,
|
||||||
autoGpuLayers,
|
autoGpuLayers,
|
||||||
handleBackendChange,
|
handleBackendChange,
|
||||||
handleGpuDeviceChange,
|
|
||||||
handleGpuLayersChange,
|
handleGpuLayersChange,
|
||||||
handleAutoGpuLayersChange,
|
handleAutoGpuLayersChange,
|
||||||
} = useLaunchConfig();
|
} = useLaunchConfig();
|
||||||
|
|
@ -72,7 +71,7 @@ export const BackendSelector = ({ onBackendsReady }: BackendSelectorProps) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Group justify="space-between" align="flex-start" mb="xs">
|
<Group justify="space-between" align="flex-start" mb="xs">
|
||||||
<div style={{ flex: 1, marginRight: '2rem' }}>
|
<div style={{ flex: 1, marginRight: '1rem' }}>
|
||||||
<Group gap="xs" align="center" mb="xs">
|
<Group gap="xs" align="center" mb="xs">
|
||||||
<Text size="sm" fw={500}>
|
<Text size="sm" fw={500}>
|
||||||
Backend
|
Backend
|
||||||
|
|
@ -104,33 +103,6 @@ export const BackendSelector = ({ onBackendsReady }: BackendSelectorProps) => {
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{(() => {
|
|
||||||
const selectedBackend = availableBackends.find(
|
|
||||||
(b) => b.value === backend
|
|
||||||
);
|
|
||||||
const isGpuBackend = backend === 'cuda' || backend === 'rocm';
|
|
||||||
const hasMultipleDevices =
|
|
||||||
selectedBackend?.devices && selectedBackend.devices.length > 1;
|
|
||||||
|
|
||||||
return (
|
|
||||||
isGpuBackend &&
|
|
||||||
hasMultipleDevices && (
|
|
||||||
<Select
|
|
||||||
label="GPU Device"
|
|
||||||
placeholder="Select GPU device"
|
|
||||||
value={gpuDevice.toString()}
|
|
||||||
onChange={(value) =>
|
|
||||||
value && handleGpuDeviceChange(parseInt(value, 10))
|
|
||||||
}
|
|
||||||
data={selectedBackend.devices!.map((device, index) => ({
|
|
||||||
value: index.toString(),
|
|
||||||
label: `GPU ${index}: ${device}`,
|
|
||||||
}))}
|
|
||||||
mt="xs"
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
})()}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
|
|
@ -169,6 +141,8 @@ export const BackendSelector = ({ onBackendsReady }: BackendSelectorProps) => {
|
||||||
</Group>
|
</Group>
|
||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
<GpuDeviceSelector availableBackends={availableBackends} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
100
src/components/screens/Launch/GeneralTab/GpuDeviceSelector.tsx
Normal file
100
src/components/screens/Launch/GeneralTab/GpuDeviceSelector.tsx
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
import { Text, Group, Select, TextInput } from '@mantine/core';
|
||||||
|
import { InfoTooltip } from '@/components/InfoTooltip';
|
||||||
|
import { useLaunchConfig } from '@/hooks/useLaunchConfig';
|
||||||
|
|
||||||
|
interface GpuDeviceSelectorProps {
|
||||||
|
availableBackends: Array<{
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
devices?: string[];
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GpuDeviceSelector = ({
|
||||||
|
availableBackends,
|
||||||
|
}: GpuDeviceSelectorProps) => {
|
||||||
|
const {
|
||||||
|
backend,
|
||||||
|
gpuDeviceSelection,
|
||||||
|
tensorSplit,
|
||||||
|
handleGpuDeviceSelectionChange,
|
||||||
|
handleTensorSplitChange,
|
||||||
|
} = useLaunchConfig();
|
||||||
|
|
||||||
|
const selectedBackend = availableBackends.find((b) => b.value === backend);
|
||||||
|
const isGpuBackend =
|
||||||
|
backend === 'cuda' ||
|
||||||
|
backend === 'rocm' ||
|
||||||
|
backend === 'vulkan' ||
|
||||||
|
backend === 'clblast';
|
||||||
|
const hasMultipleDevices =
|
||||||
|
selectedBackend?.devices && selectedBackend.devices.length > 1;
|
||||||
|
const showTensorSplit =
|
||||||
|
(backend === 'cuda' || backend === 'rocm' || backend === 'vulkan') &&
|
||||||
|
hasMultipleDevices &&
|
||||||
|
gpuDeviceSelection === 'all';
|
||||||
|
|
||||||
|
if (!isGpuBackend || !hasMultipleDevices) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deviceOptions =
|
||||||
|
backend === 'clblast'
|
||||||
|
? selectedBackend.devices!.map((device, index) => ({
|
||||||
|
value: index.toString(),
|
||||||
|
label: `GPU ${index}: ${device}`,
|
||||||
|
}))
|
||||||
|
: [
|
||||||
|
{ value: 'all', label: 'All GPUs' },
|
||||||
|
...selectedBackend.devices!.map((device, index) => ({
|
||||||
|
value: index.toString(),
|
||||||
|
label: `GPU ${index}: ${device}`,
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Group align="flex-start" gap="md">
|
||||||
|
<div style={{ flex: 1, marginRight: '1rem' }}>
|
||||||
|
<Group gap="xs" align="center" mb="xs">
|
||||||
|
<Text size="sm" fw={500}>
|
||||||
|
GPU Device
|
||||||
|
</Text>
|
||||||
|
<InfoTooltip label="Select which GPU device(s) to use. Choose 'All GPUs' to use multiple devices with tensor splitting." />
|
||||||
|
</Group>
|
||||||
|
<Select
|
||||||
|
placeholder="Select GPU device"
|
||||||
|
value={gpuDeviceSelection}
|
||||||
|
onChange={(value) => {
|
||||||
|
if (value) {
|
||||||
|
handleGpuDeviceSelectionChange(value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
data={deviceOptions}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
{showTensorSplit && (
|
||||||
|
<>
|
||||||
|
<Group gap="xs" align="center" mb="xs">
|
||||||
|
<Text size="sm" fw={500}>
|
||||||
|
Tensor Split
|
||||||
|
</Text>
|
||||||
|
<InfoTooltip label='When using multiple GPUs this option controls how large tensors should be split across all GPUs. Uses a comma-separated list of non-negative values that assigns the proportion of data that each GPU should get in order. For example, "3,2" will assign 60% of the data to GPU 0 and 40% to GPU 1.' />
|
||||||
|
</Group>
|
||||||
|
<TextInput
|
||||||
|
placeholder="e.g., 3,2 or 1,1,1"
|
||||||
|
value={tensorSplit}
|
||||||
|
onChange={(event) =>
|
||||||
|
handleTensorSplitChange(event.target.value)
|
||||||
|
}
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Group>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import { Stack, Text, Group, TextInput, Button, Slider } from '@mantine/core';
|
import { Stack, Text, Group, TextInput, Slider } from '@mantine/core';
|
||||||
import { File, Search } from 'lucide-react';
|
|
||||||
import { InfoTooltip } from '@/components/InfoTooltip';
|
import { InfoTooltip } from '@/components/InfoTooltip';
|
||||||
import { BackendSelector } from '@/components/screens/Launch/GeneralTab/BackendSelector';
|
import { BackendSelector } from '@/components/screens/Launch/GeneralTab/BackendSelector';
|
||||||
import { getInputValidationState } from '@/utils';
|
import { ModelFileField } from '@/components/ModelFileField';
|
||||||
import { useLaunchConfig } from '@/hooks/useLaunchConfig';
|
import { useLaunchConfig } from '@/hooks/useLaunchConfig';
|
||||||
import styles from '@/styles/layout.module.css';
|
|
||||||
|
|
||||||
interface GeneralTabProps {
|
interface GeneralTabProps {
|
||||||
onBackendsReady?: () => void;
|
onBackendsReady?: () => void;
|
||||||
|
|
@ -19,57 +17,20 @@ export const GeneralTab = ({ onBackendsReady }: GeneralTabProps) => {
|
||||||
handleContextSizeChangeWithStep,
|
handleContextSizeChangeWithStep,
|
||||||
} = useLaunchConfig();
|
} = useLaunchConfig();
|
||||||
|
|
||||||
const validationState = getInputValidationState(modelPath);
|
|
||||||
|
|
||||||
const getHelperText = () => {
|
|
||||||
if (!modelPath.trim()) return undefined;
|
|
||||||
|
|
||||||
if (validationState === 'invalid') {
|
|
||||||
return 'Enter a valid URL or file path to the .gguf';
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<BackendSelector onBackendsReady={onBackendsReady} />
|
<BackendSelector onBackendsReady={onBackendsReady} />
|
||||||
|
|
||||||
<div>
|
<ModelFileField
|
||||||
<Text size="sm" fw={500} mb="xs">
|
label="Text Model File"
|
||||||
Text Model File
|
|
||||||
</Text>
|
|
||||||
<Group gap="xs" align="flex-start">
|
|
||||||
<div className={styles.flex1}>
|
|
||||||
<TextInput
|
|
||||||
placeholder="Select a .gguf model file or enter a direct URL to file"
|
|
||||||
value={modelPath}
|
value={modelPath}
|
||||||
onChange={(e) => handleModelPathChange(e.target.value)}
|
placeholder="Select a .gguf model file or enter a direct URL to file"
|
||||||
error={
|
tooltip="Select a GGUF text generation model file for chat and completion tasks."
|
||||||
validationState === 'invalid' ? getHelperText() : undefined
|
onChange={handleModelPathChange}
|
||||||
}
|
onSelectFile={handleSelectModelFile}
|
||||||
|
showSearchHF
|
||||||
|
searchUrl="https://huggingface.co/models?pipeline_tag=text-generation&library=gguf&sort=trending"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
onClick={handleSelectModelFile}
|
|
||||||
variant="light"
|
|
||||||
leftSection={<File size={16} />}
|
|
||||||
>
|
|
||||||
Browse
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
window.electronAPI.app.openExternal(
|
|
||||||
'https://huggingface.co/models?pipeline_tag=text-generation&library=gguf&sort=trending'
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
variant="outline"
|
|
||||||
leftSection={<Search size={16} />}
|
|
||||||
>
|
|
||||||
Search HF
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Group justify="space-between" align="center" mb="xs">
|
<Group justify="space-between" align="center" mb="xs">
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Stack, Select } from '@mantine/core';
|
import { Stack } from '@mantine/core';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { SectionHeader } from '@/components/SectionHeader';
|
|
||||||
import { ModelFileField } from '@/components/ModelFileField';
|
import { ModelFileField } from '@/components/ModelFileField';
|
||||||
|
import { SelectWithTooltip } from '@/components/SelectWithTooltip';
|
||||||
import { IMAGE_MODEL_PRESETS } from '@/utils';
|
import { IMAGE_MODEL_PRESETS } from '@/utils';
|
||||||
import { useLaunchConfig } from '@/hooks/useLaunchConfig';
|
import { useLaunchConfig } from '@/hooks/useLaunchConfig';
|
||||||
|
|
||||||
|
|
@ -14,50 +14,54 @@ export const ImageGenerationTab = () => {
|
||||||
sdphotomaker,
|
sdphotomaker,
|
||||||
sdvae,
|
sdvae,
|
||||||
sdlora,
|
sdlora,
|
||||||
|
sdconvdirect,
|
||||||
handleSdmodelChange,
|
handleSdmodelChange,
|
||||||
handleSelectSdmodelFile,
|
|
||||||
handleSdt5xxlChange,
|
handleSdt5xxlChange,
|
||||||
handleSelectSdt5xxlFile,
|
|
||||||
handleSdcliplChange,
|
handleSdcliplChange,
|
||||||
handleSelectSdcliplFile,
|
|
||||||
handleSdclipgChange,
|
handleSdclipgChange,
|
||||||
handleSelectSdclipgFile,
|
|
||||||
handleSdphotomakerChange,
|
handleSdphotomakerChange,
|
||||||
handleSelectSdphotomakerFile,
|
|
||||||
handleSdvaeChange,
|
handleSdvaeChange,
|
||||||
handleSelectSdvaeFile,
|
|
||||||
handleSdloraChange,
|
handleSdloraChange,
|
||||||
handleSelectSdloraFile,
|
handleSdconvdirectChange,
|
||||||
handleApplyPreset,
|
handleApplyPreset,
|
||||||
|
handleSelectSdmodelFile,
|
||||||
|
handleSelectSdt5xxlFile,
|
||||||
|
handleSelectSdcliplFile,
|
||||||
|
handleSelectSdclipgFile,
|
||||||
|
handleSelectSdphotomakerFile,
|
||||||
|
handleSelectSdvaeFile,
|
||||||
|
handleSelectSdloraFile,
|
||||||
} = useLaunchConfig();
|
} = useLaunchConfig();
|
||||||
|
|
||||||
const [selectedPreset, setSelectedPreset] = useState<string | null>(null);
|
const [selectedPreset, setSelectedPreset] = useState<string | null>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<div>
|
<SelectWithTooltip
|
||||||
<SectionHeader
|
label="Model Preset"
|
||||||
title="Model Preset"
|
|
||||||
tooltip="Quick presets for popular image generation models with pre-configured encoders."
|
tooltip="Quick presets for popular image generation models with pre-configured encoders."
|
||||||
fontWeight={500}
|
|
||||||
marginBottom="xs"
|
|
||||||
/>
|
|
||||||
<Select
|
|
||||||
placeholder="Choose a preset..."
|
placeholder="Choose a preset..."
|
||||||
data={IMAGE_MODEL_PRESETS.map((preset) => ({
|
data={IMAGE_MODEL_PRESETS.map((preset) => ({
|
||||||
value: preset.name,
|
value: preset.name,
|
||||||
label: preset.name,
|
label: preset.name,
|
||||||
}))}
|
}))}
|
||||||
value={selectedPreset}
|
value={selectedPreset ?? ''}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setSelectedPreset(value);
|
setSelectedPreset(value);
|
||||||
if (value) {
|
if (value) {
|
||||||
handleApplyPreset(value);
|
handleApplyPreset(value);
|
||||||
|
} else {
|
||||||
|
handleSdmodelChange('');
|
||||||
|
handleSdt5xxlChange('');
|
||||||
|
handleSdcliplChange('');
|
||||||
|
handleSdclipgChange('');
|
||||||
|
handleSdphotomakerChange('');
|
||||||
|
handleSdvaeChange('');
|
||||||
|
handleSdloraChange('');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
clearable
|
clearable
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
|
|
||||||
<ModelFileField
|
<ModelFileField
|
||||||
label="Image Gen. Model File"
|
label="Image Gen. Model File"
|
||||||
|
|
@ -123,6 +127,22 @@ export const ImageGenerationTab = () => {
|
||||||
onChange={handleSdloraChange}
|
onChange={handleSdloraChange}
|
||||||
onSelectFile={handleSelectSdloraFile}
|
onSelectFile={handleSelectSdloraFile}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<SelectWithTooltip
|
||||||
|
label="Conv2D Direct"
|
||||||
|
tooltip="May improve performance or reduce memory usage. WARNING: Might crash if not supported by your backend! Only enable if you're sure your GPU and drivers support it."
|
||||||
|
value={sdconvdirect}
|
||||||
|
onChange={(value) => {
|
||||||
|
if (value === 'off' || value === 'vaeonly' || value === 'full') {
|
||||||
|
handleSdconvdirectChange(value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
data={[
|
||||||
|
{ value: 'off', label: 'Off' },
|
||||||
|
{ value: 'vaeonly', label: 'VAE Only' },
|
||||||
|
{ value: 'full', label: 'Full' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,8 @@ export const LaunchScreen = ({
|
||||||
quantmatmul,
|
quantmatmul,
|
||||||
usemmap,
|
usemmap,
|
||||||
backend,
|
backend,
|
||||||
gpuDevice,
|
gpuDeviceSelection,
|
||||||
|
tensorSplit,
|
||||||
gpuPlatform,
|
gpuPlatform,
|
||||||
sdmodel,
|
sdmodel,
|
||||||
sdt5xxl,
|
sdt5xxl,
|
||||||
|
|
@ -58,6 +59,7 @@ export const LaunchScreen = ({
|
||||||
sdphotomaker,
|
sdphotomaker,
|
||||||
sdvae,
|
sdvae,
|
||||||
sdlora,
|
sdlora,
|
||||||
|
sdconvdirect,
|
||||||
parseAndApplyConfigFile,
|
parseAndApplyConfigFile,
|
||||||
loadConfigFromFile,
|
loadConfigFromFile,
|
||||||
handleModelPathChange,
|
handleModelPathChange,
|
||||||
|
|
@ -180,10 +182,8 @@ export const LaunchScreen = ({
|
||||||
usecuda: backend === 'cuda' || backend === 'rocm',
|
usecuda: backend === 'cuda' || backend === 'rocm',
|
||||||
usevulkan: backend === 'vulkan',
|
usevulkan: backend === 'vulkan',
|
||||||
useclblast: backend === 'clblast',
|
useclblast: backend === 'clblast',
|
||||||
clBlastInfo:
|
gpuDeviceSelection,
|
||||||
backend === 'clblast'
|
tensorSplit,
|
||||||
? ([gpuDevice, gpuPlatform] as [number, number])
|
|
||||||
: undefined,
|
|
||||||
sdmodel,
|
sdmodel,
|
||||||
sdt5xxl,
|
sdt5xxl,
|
||||||
sdclipl,
|
sdclipl,
|
||||||
|
|
@ -285,7 +285,9 @@ export const LaunchScreen = ({
|
||||||
failsafe,
|
failsafe,
|
||||||
backend,
|
backend,
|
||||||
lowvram,
|
lowvram,
|
||||||
gpuDevice,
|
gpuDeviceSelection,
|
||||||
|
gpuPlatform,
|
||||||
|
tensorSplit,
|
||||||
quantmatmul,
|
quantmatmul,
|
||||||
usemmap,
|
usemmap,
|
||||||
additionalArguments,
|
additionalArguments,
|
||||||
|
|
@ -295,6 +297,7 @@ export const LaunchScreen = ({
|
||||||
sdphotomaker,
|
sdphotomaker,
|
||||||
sdvae,
|
sdvae,
|
||||||
sdlora,
|
sdlora,
|
||||||
|
sdconvdirect,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ export const useLaunchConfig = () => {
|
||||||
quantmatmul: state.quantmatmul,
|
quantmatmul: state.quantmatmul,
|
||||||
usemmap: state.usemmap,
|
usemmap: state.usemmap,
|
||||||
backend: state.backend,
|
backend: state.backend,
|
||||||
gpuDevice: state.gpuDevice,
|
gpuDeviceSelection: state.gpuDeviceSelection,
|
||||||
|
tensorSplit: state.tensorSplit,
|
||||||
gpuPlatform: state.gpuPlatform,
|
gpuPlatform: state.gpuPlatform,
|
||||||
sdmodel: state.sdmodel,
|
sdmodel: state.sdmodel,
|
||||||
sdt5xxl: state.sdt5xxl,
|
sdt5xxl: state.sdt5xxl,
|
||||||
|
|
@ -37,6 +38,7 @@ export const useLaunchConfig = () => {
|
||||||
sdphotomaker: state.sdphotomaker,
|
sdphotomaker: state.sdphotomaker,
|
||||||
sdvae: state.sdvae,
|
sdvae: state.sdvae,
|
||||||
sdlora: state.sdlora,
|
sdlora: state.sdlora,
|
||||||
|
sdconvdirect: state.sdconvdirect,
|
||||||
|
|
||||||
handleGpuLayersChange: state.setGpuLayers,
|
handleGpuLayersChange: state.setGpuLayers,
|
||||||
handleAutoGpuLayersChange: state.setAutoGpuLayers,
|
handleAutoGpuLayersChange: state.setAutoGpuLayers,
|
||||||
|
|
@ -58,7 +60,8 @@ export const useLaunchConfig = () => {
|
||||||
handleQuantmatmulChange: state.setQuantmatmul,
|
handleQuantmatmulChange: state.setQuantmatmul,
|
||||||
handleUsemmapChange: state.setUsemmap,
|
handleUsemmapChange: state.setUsemmap,
|
||||||
handleBackendChange: state.setBackend,
|
handleBackendChange: state.setBackend,
|
||||||
handleGpuDeviceChange: state.setGpuDevice,
|
handleGpuDeviceSelectionChange: state.setGpuDeviceSelection,
|
||||||
|
handleTensorSplitChange: state.setTensorSplit,
|
||||||
handleGpuPlatformChange: state.setGpuPlatform,
|
handleGpuPlatformChange: state.setGpuPlatform,
|
||||||
handleSdmodelChange: state.setSdmodel,
|
handleSdmodelChange: state.setSdmodel,
|
||||||
handleSdt5xxlChange: state.setSdt5xxl,
|
handleSdt5xxlChange: state.setSdt5xxl,
|
||||||
|
|
@ -67,6 +70,7 @@ export const useLaunchConfig = () => {
|
||||||
handleSdphotomakerChange: state.setSdphotomaker,
|
handleSdphotomakerChange: state.setSdphotomaker,
|
||||||
handleSdvaeChange: state.setSdvae,
|
handleSdvaeChange: state.setSdvae,
|
||||||
handleSdloraChange: state.setSdlora,
|
handleSdloraChange: state.setSdlora,
|
||||||
|
handleSdconvdirectChange: state.setSdconvdirect,
|
||||||
|
|
||||||
parseAndApplyConfigFile: state.parseAndApplyConfigFile,
|
parseAndApplyConfigFile: state.parseAndApplyConfigFile,
|
||||||
loadConfigFromFile: state.loadConfigFromFile,
|
loadConfigFromFile: state.loadConfigFromFile,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback } from 'react';
|
||||||
import { parseCLBlastDevice } from '@/utils';
|
import { parseCLBlastDevice } from '@/utils';
|
||||||
|
import type { SdConvDirectMode } from '@/types';
|
||||||
|
|
||||||
interface UseLaunchLogicProps {
|
interface UseLaunchLogicProps {
|
||||||
modelPath: string;
|
modelPath: string;
|
||||||
|
|
@ -25,7 +26,9 @@ interface LaunchArgs {
|
||||||
failsafe: boolean;
|
failsafe: boolean;
|
||||||
backend: string;
|
backend: string;
|
||||||
lowvram: boolean;
|
lowvram: boolean;
|
||||||
gpuDevice: number | string;
|
gpuDeviceSelection: string;
|
||||||
|
gpuPlatform: number;
|
||||||
|
tensorSplit: string;
|
||||||
quantmatmul: boolean;
|
quantmatmul: boolean;
|
||||||
usemmap: boolean;
|
usemmap: boolean;
|
||||||
additionalArguments: string;
|
additionalArguments: string;
|
||||||
|
|
@ -35,20 +38,18 @@ interface LaunchArgs {
|
||||||
sdphotomaker: string;
|
sdphotomaker: string;
|
||||||
sdvae: string;
|
sdvae: string;
|
||||||
sdlora: string;
|
sdlora: string;
|
||||||
|
sdconvdirect: SdConvDirectMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildModelArgs = (
|
const buildModelArgs = (
|
||||||
isImageMode: boolean,
|
isImageMode: boolean,
|
||||||
isTextMode: boolean,
|
|
||||||
modelPath: string,
|
modelPath: string,
|
||||||
sdmodel: string,
|
sdmodel: string,
|
||||||
launchArgs: LaunchArgs
|
launchArgs: LaunchArgs
|
||||||
): string[] => {
|
): string[] => {
|
||||||
const args: string[] = [];
|
const args: string[] = [];
|
||||||
|
|
||||||
if (isImageMode && isTextMode) {
|
if (isImageMode) {
|
||||||
args.push('--sdmodel', sdmodel);
|
|
||||||
} else if (isImageMode) {
|
|
||||||
args.push('--sdmodel', sdmodel);
|
args.push('--sdmodel', sdmodel);
|
||||||
|
|
||||||
const imageModels = [
|
const imageModels = [
|
||||||
|
|
@ -65,6 +66,14 @@ const buildModelArgs = (
|
||||||
args.push(flag, value);
|
args.push(flag, value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (launchArgs.flashattention) {
|
||||||
|
args.push('--sdflashattention');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (launchArgs.sdconvdirect !== 'off') {
|
||||||
|
args.push('--sdconvdirect', launchArgs.sdconvdirect);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
args.push('--model', modelPath);
|
args.push('--model', modelPath);
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +81,10 @@ const buildModelArgs = (
|
||||||
return args;
|
return args;
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildConfigArgs = (launchArgs: LaunchArgs): string[] => {
|
const buildConfigArgs = (
|
||||||
|
isImageMode: boolean,
|
||||||
|
launchArgs: LaunchArgs
|
||||||
|
): string[] => {
|
||||||
const args: string[] = [];
|
const args: string[] = [];
|
||||||
|
|
||||||
if (launchArgs.autoGpuLayers) {
|
if (launchArgs.autoGpuLayers) {
|
||||||
|
|
@ -100,7 +112,7 @@ const buildConfigArgs = (launchArgs: LaunchArgs): string[] => {
|
||||||
[launchArgs.nocertify, '--nocertify'],
|
[launchArgs.nocertify, '--nocertify'],
|
||||||
[launchArgs.websearch, '--websearch'],
|
[launchArgs.websearch, '--websearch'],
|
||||||
[launchArgs.noshift, '--noshift'],
|
[launchArgs.noshift, '--noshift'],
|
||||||
[launchArgs.flashattention, '--flashattention'],
|
[!isImageMode && launchArgs.flashattention, '--flashattention'],
|
||||||
[launchArgs.noavx2, '--noavx2'],
|
[launchArgs.noavx2, '--noavx2'],
|
||||||
[launchArgs.failsafe, '--failsafe'],
|
[launchArgs.failsafe, '--failsafe'],
|
||||||
[launchArgs.usemmap, '--usemmap'],
|
[launchArgs.usemmap, '--usemmap'],
|
||||||
|
|
@ -116,41 +128,87 @@ const buildConfigArgs = (launchArgs: LaunchArgs): string[] => {
|
||||||
return args;
|
return args;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const buildCudaArgs = (launchArgs: LaunchArgs): string[] => {
|
||||||
|
const cudaArgs = ['--usecuda'];
|
||||||
|
cudaArgs.push(launchArgs.lowvram ? 'lowvram' : 'normal');
|
||||||
|
|
||||||
|
if (launchArgs.gpuDeviceSelection === 'all') {
|
||||||
|
cudaArgs.push('0');
|
||||||
|
} else {
|
||||||
|
cudaArgs.push(launchArgs.gpuDeviceSelection || '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
cudaArgs.push(launchArgs.quantmatmul ? 'mmq' : 'nommq');
|
||||||
|
return cudaArgs;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildVulkanArgs = (): string[] => ['--usevulkan'];
|
||||||
|
|
||||||
|
const buildClblastArgs = (launchArgs: LaunchArgs): string[] => {
|
||||||
|
const clblastArgs = ['--useclblast'];
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof launchArgs.gpuDeviceSelection === 'string' &&
|
||||||
|
launchArgs.gpuDeviceSelection.includes(':')
|
||||||
|
) {
|
||||||
|
const parsed = parseCLBlastDevice(launchArgs.gpuDeviceSelection);
|
||||||
|
if (parsed) {
|
||||||
|
clblastArgs.push(
|
||||||
|
parsed.platformIndex.toString(),
|
||||||
|
parsed.deviceIndex.toString()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
clblastArgs.push(launchArgs.gpuPlatform.toString(), '0');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clblastArgs.push(
|
||||||
|
launchArgs.gpuPlatform.toString(),
|
||||||
|
launchArgs.gpuDeviceSelection || '0'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clblastArgs;
|
||||||
|
};
|
||||||
|
|
||||||
|
const addTensorSplitArgs = (args: string[], launchArgs: LaunchArgs): void => {
|
||||||
|
if (launchArgs.tensorSplit && launchArgs.tensorSplit.trim()) {
|
||||||
|
const tensorValues = launchArgs.tensorSplit
|
||||||
|
.split(',')
|
||||||
|
.map((value) => value.trim())
|
||||||
|
.filter((value) => value !== '' && !isNaN(Number(value)));
|
||||||
|
|
||||||
|
if (tensorValues.length > 0) {
|
||||||
|
args.push('--tensorsplit', ...tensorValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const buildBackendArgs = (launchArgs: LaunchArgs): string[] => {
|
const buildBackendArgs = (launchArgs: LaunchArgs): string[] => {
|
||||||
const args: string[] = [];
|
const args: string[] = [];
|
||||||
|
|
||||||
if (launchArgs.backend && launchArgs.backend !== 'cpu') {
|
if (!launchArgs.backend || launchArgs.backend === 'cpu') {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isTensorSplitSupported =
|
||||||
|
launchArgs.backend === 'cuda' ||
|
||||||
|
launchArgs.backend === 'rocm' ||
|
||||||
|
launchArgs.backend === 'vulkan';
|
||||||
|
|
||||||
if (launchArgs.backend === 'cuda' || launchArgs.backend === 'rocm') {
|
if (launchArgs.backend === 'cuda' || launchArgs.backend === 'rocm') {
|
||||||
const cudaArgs = ['--usecuda'];
|
args.push(...buildCudaArgs(launchArgs));
|
||||||
cudaArgs.push(launchArgs.lowvram ? 'lowvram' : 'normal');
|
|
||||||
cudaArgs.push(
|
if (launchArgs.gpuDeviceSelection === 'all' && isTensorSplitSupported) {
|
||||||
typeof launchArgs.gpuDevice === 'string'
|
addTensorSplitArgs(args, launchArgs);
|
||||||
? '0'
|
}
|
||||||
: launchArgs.gpuDevice.toString()
|
|
||||||
);
|
|
||||||
cudaArgs.push(launchArgs.quantmatmul ? 'mmq' : 'nommq');
|
|
||||||
args.push(...cudaArgs);
|
|
||||||
} else if (launchArgs.backend === 'vulkan') {
|
} else if (launchArgs.backend === 'vulkan') {
|
||||||
args.push('--usevulkan');
|
args.push(...buildVulkanArgs());
|
||||||
|
|
||||||
|
if (launchArgs.gpuDeviceSelection === 'all' && isTensorSplitSupported) {
|
||||||
|
addTensorSplitArgs(args, launchArgs);
|
||||||
|
}
|
||||||
} else if (launchArgs.backend === 'clblast') {
|
} else if (launchArgs.backend === 'clblast') {
|
||||||
const clblastArgs = ['--useclblast'];
|
args.push(...buildClblastArgs(launchArgs));
|
||||||
|
|
||||||
if (typeof launchArgs.gpuDevice === 'string') {
|
|
||||||
const parsed = parseCLBlastDevice(launchArgs.gpuDevice);
|
|
||||||
if (parsed) {
|
|
||||||
clblastArgs.push(
|
|
||||||
parsed.deviceIndex.toString(),
|
|
||||||
parsed.platformIndex.toString()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
clblastArgs.push('0', '0');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
clblastArgs.push(launchArgs.gpuDevice.toString(), '0');
|
|
||||||
}
|
|
||||||
|
|
||||||
args.push(...clblastArgs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
|
|
@ -177,14 +235,8 @@ export const useLaunchLogic = ({
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const args: string[] = [
|
const args: string[] = [
|
||||||
...buildModelArgs(
|
...buildModelArgs(isImageMode, modelPath, sdmodel, launchArgs),
|
||||||
isImageMode,
|
...buildConfigArgs(isImageMode, launchArgs),
|
||||||
isTextMode,
|
|
||||||
modelPath,
|
|
||||||
sdmodel,
|
|
||||||
launchArgs
|
|
||||||
),
|
|
||||||
...buildConfigArgs(launchArgs),
|
|
||||||
...buildBackendArgs(launchArgs),
|
...buildBackendArgs(launchArgs),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import type { ConfigFile } from '@/types';
|
import type { ConfigFile, SdConvDirectMode } from '@/types';
|
||||||
import type { ImageModelPreset } from '@/utils/imageModelPresets';
|
import type { ImageModelPreset } from '@/utils/imageModelPresets';
|
||||||
import { DEFAULT_CONTEXT_SIZE } from '@/constants';
|
import { DEFAULT_CONTEXT_SIZE } from '@/constants';
|
||||||
|
|
||||||
|
|
@ -24,7 +24,8 @@ interface LaunchConfigState {
|
||||||
quantmatmul: boolean;
|
quantmatmul: boolean;
|
||||||
usemmap: boolean;
|
usemmap: boolean;
|
||||||
backend: string;
|
backend: string;
|
||||||
gpuDevice: number;
|
gpuDeviceSelection: string;
|
||||||
|
tensorSplit: string;
|
||||||
gpuPlatform: number;
|
gpuPlatform: number;
|
||||||
sdmodel: string;
|
sdmodel: string;
|
||||||
sdt5xxl: string;
|
sdt5xxl: string;
|
||||||
|
|
@ -33,6 +34,7 @@ interface LaunchConfigState {
|
||||||
sdphotomaker: string;
|
sdphotomaker: string;
|
||||||
sdvae: string;
|
sdvae: string;
|
||||||
sdlora: string;
|
sdlora: string;
|
||||||
|
sdconvdirect: SdConvDirectMode;
|
||||||
|
|
||||||
setGpuLayers: (layers: number) => void;
|
setGpuLayers: (layers: number) => void;
|
||||||
setAutoGpuLayers: (auto: boolean) => void;
|
setAutoGpuLayers: (auto: boolean) => void;
|
||||||
|
|
@ -54,7 +56,8 @@ interface LaunchConfigState {
|
||||||
setQuantmatmul: (quantmatmul: boolean) => void;
|
setQuantmatmul: (quantmatmul: boolean) => void;
|
||||||
setUsemmap: (usemmap: boolean) => void;
|
setUsemmap: (usemmap: boolean) => void;
|
||||||
setBackend: (backend: string) => void;
|
setBackend: (backend: string) => void;
|
||||||
setGpuDevice: (device: number) => void;
|
setGpuDeviceSelection: (selection: string) => void;
|
||||||
|
setTensorSplit: (split: string) => void;
|
||||||
setGpuPlatform: (platform: number) => void;
|
setGpuPlatform: (platform: number) => void;
|
||||||
setSdmodel: (model: string) => void;
|
setSdmodel: (model: string) => void;
|
||||||
setSdt5xxl: (model: string) => void;
|
setSdt5xxl: (model: string) => void;
|
||||||
|
|
@ -63,6 +66,7 @@ interface LaunchConfigState {
|
||||||
setSdphotomaker: (model: string) => void;
|
setSdphotomaker: (model: string) => void;
|
||||||
setSdvae: (vae: string) => void;
|
setSdvae: (vae: string) => void;
|
||||||
setSdlora: (loraModel: string) => void;
|
setSdlora: (loraModel: string) => void;
|
||||||
|
setSdconvdirect: (mode: SdConvDirectMode) => void;
|
||||||
|
|
||||||
parseAndApplyConfigFile: (configPath: string) => Promise<void>;
|
parseAndApplyConfigFile: (configPath: string) => Promise<void>;
|
||||||
loadConfigFromFile: (
|
loadConfigFromFile: (
|
||||||
|
|
@ -102,7 +106,8 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
||||||
quantmatmul: true,
|
quantmatmul: true,
|
||||||
usemmap: true,
|
usemmap: true,
|
||||||
backend: '',
|
backend: '',
|
||||||
gpuDevice: 0,
|
gpuDeviceSelection: '0',
|
||||||
|
tensorSplit: '',
|
||||||
gpuPlatform: 0,
|
gpuPlatform: 0,
|
||||||
sdmodel: '',
|
sdmodel: '',
|
||||||
sdt5xxl: '',
|
sdt5xxl: '',
|
||||||
|
|
@ -111,6 +116,7 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
||||||
sdphotomaker: '',
|
sdphotomaker: '',
|
||||||
sdvae: '',
|
sdvae: '',
|
||||||
sdlora: '',
|
sdlora: '',
|
||||||
|
sdconvdirect: 'off' as const,
|
||||||
|
|
||||||
setGpuLayers: (layers) => set({ gpuLayers: layers }),
|
setGpuLayers: (layers) => set({ gpuLayers: layers }),
|
||||||
setAutoGpuLayers: (auto) => set({ autoGpuLayers: auto }),
|
setAutoGpuLayers: (auto) => set({ autoGpuLayers: auto }),
|
||||||
|
|
@ -131,8 +137,14 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
||||||
setLowvram: (lowvram) => set({ lowvram }),
|
setLowvram: (lowvram) => set({ lowvram }),
|
||||||
setQuantmatmul: (quantmatmul) => set({ quantmatmul }),
|
setQuantmatmul: (quantmatmul) => set({ quantmatmul }),
|
||||||
setUsemmap: (usemmap) => set({ usemmap }),
|
setUsemmap: (usemmap) => set({ usemmap }),
|
||||||
setBackend: (backend) => set({ backend }),
|
setBackend: (backend) =>
|
||||||
setGpuDevice: (device) => set({ gpuDevice: device }),
|
set({
|
||||||
|
backend,
|
||||||
|
gpuDeviceSelection: '0',
|
||||||
|
tensorSplit: '',
|
||||||
|
}),
|
||||||
|
setGpuDeviceSelection: (selection) => set({ gpuDeviceSelection: selection }),
|
||||||
|
setTensorSplit: (split) => set({ tensorSplit: split }),
|
||||||
setGpuPlatform: (platform) => set({ gpuPlatform: platform }),
|
setGpuPlatform: (platform) => set({ gpuPlatform: platform }),
|
||||||
setSdmodel: (model) => set({ sdmodel: model }),
|
setSdmodel: (model) => set({ sdmodel: model }),
|
||||||
setSdt5xxl: (model) => set({ sdt5xxl: model }),
|
setSdt5xxl: (model) => set({ sdt5xxl: model }),
|
||||||
|
|
@ -141,6 +153,7 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
||||||
setSdphotomaker: (model) => set({ sdphotomaker: model }),
|
setSdphotomaker: (model) => set({ sdphotomaker: model }),
|
||||||
setSdvae: (vae) => set({ sdvae: vae }),
|
setSdvae: (vae) => set({ sdvae: vae }),
|
||||||
setSdlora: (loraModel) => set({ sdlora: loraModel }),
|
setSdlora: (loraModel) => set({ sdlora: loraModel }),
|
||||||
|
setSdconvdirect: (mode) => set({ sdconvdirect: mode }),
|
||||||
|
|
||||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
parseAndApplyConfigFile: async (configPath: string) => {
|
parseAndApplyConfigFile: async (configPath: string) => {
|
||||||
|
|
@ -262,7 +275,7 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
||||||
) {
|
) {
|
||||||
const [vramMode, deviceId, mmqMode] = configData.usecuda;
|
const [vramMode, deviceId, mmqMode] = configData.usecuda;
|
||||||
updates.lowvram = vramMode === 'lowvram';
|
updates.lowvram = vramMode === 'lowvram';
|
||||||
updates.gpuDevice = parseInt(deviceId, 10) || 0;
|
updates.gpuDeviceSelection = deviceId || '0';
|
||||||
updates.quantmatmul = mmqMode === 'mmq';
|
updates.quantmatmul = mmqMode === 'mmq';
|
||||||
}
|
}
|
||||||
} else if (configData.usevulkan === true) {
|
} else if (configData.usevulkan === true) {
|
||||||
|
|
@ -273,12 +286,20 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
||||||
) {
|
) {
|
||||||
updates.backend = 'clblast';
|
updates.backend = 'clblast';
|
||||||
const [deviceIndex, platformIndex] = configData.useclblast;
|
const [deviceIndex, platformIndex] = configData.useclblast;
|
||||||
updates.gpuDevice = deviceIndex;
|
updates.gpuDeviceSelection = deviceIndex.toString();
|
||||||
updates.gpuPlatform = platformIndex;
|
updates.gpuPlatform = platformIndex;
|
||||||
} else {
|
} else {
|
||||||
updates.backend = 'cpu';
|
updates.backend = 'cpu';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof configData.gpuDeviceSelection === 'string') {
|
||||||
|
updates.gpuDeviceSelection = configData.gpuDeviceSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof configData.tensorSplit === 'string') {
|
||||||
|
updates.tensorSplit = configData.tensorSplit;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof configData.sdmodel === 'string') {
|
if (typeof configData.sdmodel === 'string') {
|
||||||
updates.sdmodel = configData.sdmodel;
|
updates.sdmodel = configData.sdmodel;
|
||||||
}
|
}
|
||||||
|
|
@ -306,6 +327,12 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
||||||
if (typeof configData.sdlora === 'string') {
|
if (typeof configData.sdlora === 'string') {
|
||||||
updates.sdlora = configData.sdlora;
|
updates.sdlora = configData.sdlora;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
typeof configData.sdconvdirect === 'string' &&
|
||||||
|
['off', 'vaeonly', 'full'].includes(configData.sdconvdirect)
|
||||||
|
) {
|
||||||
|
updates.sdconvdirect = configData.sdconvdirect as SdConvDirectMode;
|
||||||
|
}
|
||||||
|
|
||||||
set(updates);
|
set(updates);
|
||||||
}
|
}
|
||||||
|
|
@ -396,6 +423,7 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
||||||
|
|
||||||
applyImageModelPreset: (preset: ImageModelPreset) => {
|
applyImageModelPreset: (preset: ImageModelPreset) => {
|
||||||
set({
|
set({
|
||||||
|
sdmodel: preset.sdmodel,
|
||||||
sdt5xxl: preset.sdt5xxl,
|
sdt5xxl: preset.sdt5xxl,
|
||||||
sdclipl: preset.sdclipl,
|
sdclipl: preset.sdclipl,
|
||||||
sdclipg: preset.sdclipg || '',
|
sdclipg: preset.sdclipg || '',
|
||||||
|
|
|
||||||
1
src/types/electron.d.ts
vendored
1
src/types/electron.d.ts
vendored
|
|
@ -121,7 +121,6 @@ export interface KoboldAPI {
|
||||||
usecuda?: boolean;
|
usecuda?: boolean;
|
||||||
usevulkan?: boolean;
|
usevulkan?: boolean;
|
||||||
useclblast?: boolean;
|
useclblast?: boolean;
|
||||||
clBlastInfo?: [number, number];
|
|
||||||
sdmodel?: string;
|
sdmodel?: string;
|
||||||
sdt5xxl?: string;
|
sdt5xxl?: string;
|
||||||
sdclipl?: string;
|
sdclipl?: string;
|
||||||
|
|
|
||||||
6
src/types/index.d.ts
vendored
6
src/types/index.d.ts
vendored
|
|
@ -4,6 +4,12 @@ export interface ConfigFile {
|
||||||
size: number;
|
size: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type InterfaceTab = 'terminal' | 'chat';
|
||||||
|
|
||||||
|
export type SdConvDirectMode = 'off' | 'vaeonly' | 'full';
|
||||||
|
|
||||||
|
export type ServerTabMode = 'chat' | 'image-generation';
|
||||||
|
|
||||||
export interface GitHubAsset {
|
export interface GitHubAsset {
|
||||||
name: string;
|
name: string;
|
||||||
browser_download_url: string;
|
browser_download_url: string;
|
||||||
|
|
|
||||||
|
|
@ -38,14 +38,4 @@ export const IMAGE_MODEL_PRESETS: ImageModelPreset[] = [
|
||||||
sdvae:
|
sdvae:
|
||||||
'https://huggingface.co/lodestones/Chroma/resolve/main/ae.safetensors?download=true',
|
'https://huggingface.co/lodestones/Chroma/resolve/main/ae.safetensors?download=true',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'Custom',
|
|
||||||
description: 'Start with empty fields for custom configuration',
|
|
||||||
sdmodel: '',
|
|
||||||
sdt5xxl: '',
|
|
||||||
sdclipl: '',
|
|
||||||
sdclipg: '',
|
|
||||||
sdphotomaker: '',
|
|
||||||
sdvae: '',
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue