| | |
| | | isDefault: boolean |
| | | downloadSize?: string |
| | | description?: string |
| | | supportedInBuild?: boolean |
| | | unsupportedReason?: string |
| | | } |
| | | |
| | | interface LanguageOption { |
| | |
| | | } |
| | | |
| | | function modelTierLabel(option: ModelOption): string { |
| | | if (!modelSupported(option)) return t('settings.modelUnavailable') |
| | | if (option.isDefault) return t('settings.modelDefault') |
| | | if (option.tier === 'advanced') return t('settings.modelAdvanced') |
| | | return option.tier || '' |
| | | } |
| | | |
| | | function modelSupported(option: ModelOption): boolean { |
| | | return option.supportedInBuild !== false |
| | | } |
| | | |
| | | function modelUnsupportedText(option: ModelOption): string { |
| | | if (option.unsupportedReason === 'requires_macos_14') { |
| | | return t('models.qwen3RequiresMacOS14') |
| | | } |
| | | return t('settings.modelUnavailable') |
| | | } |
| | | |
| | | function modelActionLabel(option: ModelOption): string { |
| | | if (!modelSupported(option)) return t('settings.modelUnavailable') |
| | | if (modelBusyID === option.modelID) { |
| | | if (modelBusyKind === 'download') { |
| | | return modelCancellingID === option.modelID ? t('settings.modelCancelling') : t('settings.modelCancel') |
| | |
| | | |
| | | function modelMeta(option: ModelOption): string { |
| | | let meta = option.installed ? t('settings.modelInstalled') : t('settings.modelNotInstalled') |
| | | if (!modelSupported(option)) { |
| | | return `${meta} · ${modelUnsupportedText(option)}` |
| | | } |
| | | if (option.downloadSize) { |
| | | meta += ` · ${option.downloadSize}` |
| | | } |
| | |
| | | } |
| | | |
| | | async function onModelAction(option: ModelOption) { |
| | | if ((option.isCurrent && option.installed) || modelBusyID) return |
| | | if (!modelSupported(option) || (option.isCurrent && option.installed) || modelBusyID) return |
| | | modelBusyID = option.modelID |
| | | modelBusyKind = option.installed ? 'select' : 'download' |
| | | modelProgress = 0 |
| | |
| | | |
| | | <div class="model-list"> |
| | | {#each modelOptions as option} |
| | | <div class="model-card" class:current={option.isCurrent}> |
| | | <div class="model-card" class:current={option.isCurrent} class:unsupported={!modelSupported(option)}> |
| | | <div class="model-main"> |
| | | <div class="model-title-row"> |
| | | <span class="model-title">{option.displayName}</span> |
| | |
| | | <button |
| | | class="model-action primary" |
| | | class:cancel={canCancelModel(option)} |
| | | disabled={!!modelBusyID && modelBusyID !== option.modelID} |
| | | disabled={!modelSupported(option) || (!!modelBusyID && modelBusyID !== option.modelID)} |
| | | onclick={() => onModelButton(option)} |
| | | > |
| | | {modelActionLabel(option)} |
| | |
| | | background: rgba(0, 122, 255, 0.055); |
| | | } |
| | | |
| | | .model-card.unsupported { |
| | | opacity: 0.76; |
| | | } |
| | | |
| | | .model-card.current::before { |
| | | content: ''; |
| | | position: absolute; |