diff --git a/desktop/src/electron/service-bridge/engine-settings.ts b/desktop/src/electron/service-bridge/engine-settings.ts index bc74bf61e..313f62c58 100644 --- a/desktop/src/electron/service-bridge/engine-settings.ts +++ b/desktop/src/electron/service-bridge/engine-settings.ts @@ -39,10 +39,14 @@ function isReceiptPhase(value: JsonValue | undefined): value is EngineSettingsRe } function config(value: JsonValue | undefined): EngineSettingsConfig { const row = object(value) + const modelSource = row.modelSource + if (modelSource !== undefined && modelSource !== 'huggingface' && modelSource !== 'modelscope') + throw new Error('Invalid model download source.') return { serverPort: number(row.serverPort), proxyPort: number(row.proxyPort), - launchText: text(row.launchText) + launchText: text(row.launchText), + ...(modelSource ? { modelSource } : {}) } } export function parseEngineSettings(value: JsonValue | undefined): EngineSettingsSnapshot { diff --git a/desktop/src/shared/types/engine-settings.ts b/desktop/src/shared/types/engine-settings.ts index 02311a343..34c875832 100644 --- a/desktop/src/shared/types/engine-settings.ts +++ b/desktop/src/shared/types/engine-settings.ts @@ -6,6 +6,7 @@ export interface EngineSettingsConfig { proxyPort: number /** Arguments and leading environment assignments, without an executable/subcommand. */ launchText: string + modelSource?: 'huggingface' | 'modelscope' } import type { EngineManagerName } from '@/shared/types/engines' diff --git a/desktop/src/ui/components/BackendRow/EngineSettingsSection.tsx b/desktop/src/ui/components/BackendRow/EngineSettingsSection.tsx index bc038359c..6be4dc281 100644 --- a/desktop/src/ui/components/BackendRow/EngineSettingsSection.tsx +++ b/desktop/src/ui/components/BackendRow/EngineSettingsSection.tsx @@ -10,6 +10,7 @@ import { ModalDialog, ModalHeading, ModalRoot, + Select, Stack, Text, TextArea, @@ -36,14 +37,19 @@ interface Draft { serverPort: string proxyPort: string launchText: string + modelSource: NonNullable } const asDraft = (config: EngineSettingsConfig): Draft => ({ ...config, serverPort: String(config.serverPort), - proxyPort: String(config.proxyPort) + proxyPort: String(config.proxyPort), + modelSource: config.modelSource ?? 'huggingface' }) const sameDraft = (a: Draft, b: Draft): boolean => - a.serverPort === b.serverPort && a.proxyPort === b.proxyPort && a.launchText === b.launchText + a.serverPort === b.serverPort && + a.proxyPort === b.proxyPort && + a.launchText === b.launchText && + a.modelSource === b.modelSource export function EngineSettingsSection({ nodeId, @@ -61,7 +67,12 @@ export function EngineSettingsSection({ const connected = useConnectionStore(state => state.connected) const isLocalNode = useConnectionStore(state => state.selfId === nodeId) const [base, setBase] = useState() - const [draft, setDraft] = useState({ serverPort: '', proxyPort: '', launchText: '' }) + const [draft, setDraft] = useState({ + serverPort: '', + proxyPort: '', + launchText: '', + modelSource: 'huggingface' + }) const [errorDialog, setErrorDialog] = useState('') const [confirmation, setConfirmation] = useState() const [checking, setChecking] = useState(false) @@ -109,7 +120,7 @@ export function EngineSettingsSection({ } }, [snapshot, base, dirty]) - function change(field: keyof Draft, value: string): void { + function change(field: K, value: Draft[K]): void { generation.current++ if (field === 'serverPort') serverPortEdited.current = true setDraft(current => ({ ...current, [field]: value })) @@ -142,7 +153,12 @@ export function EngineSettingsSection({ const request: EngineSettingsRequest = { ...target, expectedRevision: base.revision, - settings: { serverPort, proxyPort, launchText: draft.launchText }, + settings: { + serverPort, + proxyPort, + launchText: draft.launchText, + ...(engineType === 'llama-cpp' ? { modelSource: draft.modelSource } : {}) + }, resolution: useServerPort ? 'server' : 'launch' } try { @@ -254,6 +270,24 @@ export function EngineSettingsSection({ /> + {engineType === 'llama-cpp' && ( + +