fix: Apply model name change correctly
# Conflicts: # web-app/src/lib/utils.ts
This commit is contained in:
parent
75dee86375
commit
03ee9c14a3
1
src-tauri/Cargo.lock
generated
1
src-tauri/Cargo.lock
generated
@ -5323,6 +5323,7 @@ dependencies = [
|
|||||||
"sysinfo",
|
"sysinfo",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-plugin",
|
"tauri-plugin",
|
||||||
|
"tauri-plugin-hardware",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from '@/components/ui/popover'
|
} from '@/components/ui/popover'
|
||||||
import { useModelProvider } from '@/hooks/useModelProvider'
|
import { useModelProvider } from '@/hooks/useModelProvider'
|
||||||
import { cn, getProviderTitle } from '@/lib/utils'
|
import { cn, getProviderTitle, getModelDisplayName } from '@/lib/utils'
|
||||||
import { highlightFzfMatch } from '@/utils/highlight'
|
import { highlightFzfMatch } from '@/utils/highlight'
|
||||||
import Capabilities from './Capabilities'
|
import Capabilities from './Capabilities'
|
||||||
import { IconSettings, IconX } from '@tabler/icons-react'
|
import { IconSettings, IconX } from '@tabler/icons-react'
|
||||||
@ -240,7 +240,7 @@ const DropdownModelProvider = ({
|
|||||||
// Update display model when selection changes
|
// Update display model when selection changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedProvider && selectedModel) {
|
if (selectedProvider && selectedModel) {
|
||||||
setDisplayModel(selectedModel.id)
|
setDisplayModel(getModelDisplayName(selectedModel))
|
||||||
} else {
|
} else {
|
||||||
setDisplayModel(t('common:selectAModel'))
|
setDisplayModel(t('common:selectAModel'))
|
||||||
}
|
}
|
||||||
@ -326,7 +326,7 @@ const DropdownModelProvider = ({
|
|||||||
// Create Fzf instance for fuzzy search
|
// Create Fzf instance for fuzzy search
|
||||||
const fzfInstance = useMemo(() => {
|
const fzfInstance = useMemo(() => {
|
||||||
return new Fzf(searchableItems, {
|
return new Fzf(searchableItems, {
|
||||||
selector: (item) => item.model.id.toLowerCase(),
|
selector: (item) => `${getModelDisplayName(item.model)} ${item.model.id}`.toLowerCase(),
|
||||||
})
|
})
|
||||||
}, [searchableItems])
|
}, [searchableItems])
|
||||||
|
|
||||||
@ -390,7 +390,7 @@ const DropdownModelProvider = ({
|
|||||||
const handleSelect = useCallback(
|
const handleSelect = useCallback(
|
||||||
async (searchableModel: SearchableModel) => {
|
async (searchableModel: SearchableModel) => {
|
||||||
// Immediately update display to prevent double-click issues
|
// Immediately update display to prevent double-click issues
|
||||||
setDisplayModel(searchableModel.model.id)
|
setDisplayModel(getModelDisplayName(searchableModel.model))
|
||||||
setSearchValue('')
|
setSearchValue('')
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
|
|
||||||
@ -576,7 +576,7 @@ const DropdownModelProvider = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-main-view-fg/80 text-sm">
|
<span className="text-main-view-fg/80 text-sm">
|
||||||
{searchableModel.model.id}
|
{getModelDisplayName(searchableModel.model)}
|
||||||
</span>
|
</span>
|
||||||
<div className="flex-1"></div>
|
<div className="flex-1"></div>
|
||||||
{capabilities.length > 0 && (
|
{capabilities.length > 0 && (
|
||||||
@ -669,7 +669,7 @@ const DropdownModelProvider = ({
|
|||||||
className="text-main-view-fg/80 text-sm"
|
className="text-main-view-fg/80 text-sm"
|
||||||
title={searchableModel.model.id}
|
title={searchableModel.model.id}
|
||||||
>
|
>
|
||||||
{searchableModel.model.id}
|
{getModelDisplayName(searchableModel.model)}
|
||||||
</span>
|
</span>
|
||||||
<div className="flex-1"></div>
|
<div className="flex-1"></div>
|
||||||
{capabilities.length > 0 && (
|
{capabilities.length > 0 && (
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import { Button } from '@/components/ui/button'
|
|||||||
import { DynamicControllerSetting } from '@/containers/dynamicControllerSetting'
|
import { DynamicControllerSetting } from '@/containers/dynamicControllerSetting'
|
||||||
import { useModelProvider } from '@/hooks/useModelProvider'
|
import { useModelProvider } from '@/hooks/useModelProvider'
|
||||||
import { useServiceHub } from '@/hooks/useServiceHub'
|
import { useServiceHub } from '@/hooks/useServiceHub'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn, getModelDisplayName } from '@/lib/utils'
|
||||||
import { useTranslation } from '@/i18n/react-i18next-compat'
|
import { useTranslation } from '@/i18n/react-i18next-compat'
|
||||||
|
|
||||||
type ModelSettingProps = {
|
type ModelSettingProps = {
|
||||||
@ -261,7 +261,7 @@ export function ModelSetting({
|
|||||||
<SheetContent className="h-[calc(100%-8px)] top-1 right-1 rounded-e-md overflow-y-auto">
|
<SheetContent className="h-[calc(100%-8px)] top-1 right-1 rounded-e-md overflow-y-auto">
|
||||||
<SheetHeader>
|
<SheetHeader>
|
||||||
<SheetTitle>
|
<SheetTitle>
|
||||||
{t('common:modelSettings.title', { modelId: model.id })}
|
{t('common:modelSettings.title', { modelId: getModelDisplayName(model) })}
|
||||||
</SheetTitle>
|
</SheetTitle>
|
||||||
<SheetDescription>
|
<SheetDescription>
|
||||||
{t('common:modelSettings.description')}
|
{t('common:modelSettings.description')}
|
||||||
|
|||||||
@ -39,8 +39,8 @@ export const DialogEditModel = ({
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { updateProvider, setProviders } = useModelProvider()
|
const { updateProvider, setProviders } = useModelProvider()
|
||||||
const [selectedModelId, setSelectedModelId] = useState<string>('')
|
const [selectedModelId, setSelectedModelId] = useState<string>('')
|
||||||
const [modelName, setModelName] = useState<string>('')
|
const [displayName, setDisplayName] = useState<string>('')
|
||||||
const [originalModelName, setOriginalModelName] = useState<string>('')
|
const [originalDisplayName, setOriginalDisplayName] = useState<string>('')
|
||||||
const [originalCapabilities, setOriginalCapabilities] = useState<
|
const [originalCapabilities, setOriginalCapabilities] = useState<
|
||||||
Record<string, boolean>
|
Record<string, boolean>
|
||||||
>({})
|
>({})
|
||||||
@ -86,7 +86,7 @@ export const DialogEditModel = ({
|
|||||||
(m: any) => m.id === selectedModelId
|
(m: any) => m.id === selectedModelId
|
||||||
)
|
)
|
||||||
|
|
||||||
// Initialize capabilities and model name from selected model
|
// Initialize capabilities and display name from selected model
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedModel) {
|
if (selectedModel) {
|
||||||
const modelCapabilities = selectedModel.capabilities || []
|
const modelCapabilities = selectedModel.capabilities || []
|
||||||
@ -98,9 +98,10 @@ export const DialogEditModel = ({
|
|||||||
web_search: modelCapabilities.includes('web_search'),
|
web_search: modelCapabilities.includes('web_search'),
|
||||||
reasoning: modelCapabilities.includes('reasoning'),
|
reasoning: modelCapabilities.includes('reasoning'),
|
||||||
})
|
})
|
||||||
const modelNameValue = selectedModel.id
|
// Use existing displayName if available, otherwise fall back to model ID
|
||||||
setModelName(modelNameValue)
|
const displayNameValue = (selectedModel as any).displayName || selectedModel.id
|
||||||
setOriginalModelName(modelNameValue)
|
setDisplayName(displayNameValue)
|
||||||
|
setOriginalDisplayName(displayNameValue)
|
||||||
|
|
||||||
const originalCaps = {
|
const originalCaps = {
|
||||||
completion: modelCapabilities.includes('completion'),
|
completion: modelCapabilities.includes('completion'),
|
||||||
@ -122,14 +123,14 @@ export const DialogEditModel = ({
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle model name change
|
// Handle display name change
|
||||||
const handleModelNameChange = (newName: string) => {
|
const handleDisplayNameChange = (newName: string) => {
|
||||||
setModelName(newName)
|
setDisplayName(newName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there are unsaved changes
|
// Check if there are unsaved changes
|
||||||
const hasUnsavedChanges = () => {
|
const hasUnsavedChanges = () => {
|
||||||
const nameChanged = modelName !== originalModelName
|
const nameChanged = displayName !== originalDisplayName
|
||||||
const capabilitiesChanged =
|
const capabilitiesChanged =
|
||||||
JSON.stringify(capabilities) !== JSON.stringify(originalCapabilities)
|
JSON.stringify(capabilities) !== JSON.stringify(originalCapabilities)
|
||||||
return nameChanged || capabilitiesChanged
|
return nameChanged || capabilitiesChanged
|
||||||
@ -141,13 +142,21 @@ export const DialogEditModel = ({
|
|||||||
|
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
try {
|
try {
|
||||||
// Update model name if changed
|
let updatedModels = provider.models
|
||||||
if (modelName !== originalModelName) {
|
|
||||||
await serviceHub
|
// Update display name if changed
|
||||||
.models()
|
if (displayName !== originalDisplayName) {
|
||||||
.updateModel(selectedModel.id, { id: modelName })
|
// Update the model in the provider models array with displayName
|
||||||
setOriginalModelName(modelName)
|
updatedModels = updatedModels.map((m: any) => {
|
||||||
await serviceHub.providers().getProviders().then(setProviders)
|
if (m.id === selectedModelId) {
|
||||||
|
return {
|
||||||
|
...m,
|
||||||
|
displayName: displayName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
})
|
||||||
|
setOriginalDisplayName(displayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update capabilities if changed
|
// Update capabilities if changed
|
||||||
@ -159,8 +168,7 @@ export const DialogEditModel = ({
|
|||||||
.map(([capName]) => capName)
|
.map(([capName]) => capName)
|
||||||
|
|
||||||
// Find and update the model in the provider
|
// Find and update the model in the provider
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
updatedModels = updatedModels.map((m: any) => {
|
||||||
const updatedModels = provider.models.map((m: any) => {
|
|
||||||
if (m.id === selectedModelId) {
|
if (m.id === selectedModelId) {
|
||||||
return {
|
return {
|
||||||
...m,
|
...m,
|
||||||
@ -172,15 +180,15 @@ export const DialogEditModel = ({
|
|||||||
return m
|
return m
|
||||||
})
|
})
|
||||||
|
|
||||||
// Update the provider with the updated models
|
|
||||||
updateProvider(provider.provider, {
|
|
||||||
...provider,
|
|
||||||
models: updatedModels,
|
|
||||||
})
|
|
||||||
|
|
||||||
setOriginalCapabilities(capabilities)
|
setOriginalCapabilities(capabilities)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the provider with the updated models
|
||||||
|
updateProvider(provider.provider, {
|
||||||
|
...provider,
|
||||||
|
models: updatedModels,
|
||||||
|
})
|
||||||
|
|
||||||
// Show success toast and close dialog
|
// Show success toast and close dialog
|
||||||
toast.success('Model updated successfully')
|
toast.success('Model updated successfully')
|
||||||
setIsOpen(false)
|
setIsOpen(false)
|
||||||
@ -213,22 +221,25 @@ export const DialogEditModel = ({
|
|||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
{/* Model Name Section */}
|
{/* Model Display Name Section */}
|
||||||
<div className="py-1">
|
<div className="py-1">
|
||||||
<label
|
<label
|
||||||
htmlFor="model-name"
|
htmlFor="display-name"
|
||||||
className="text-sm font-medium mb-3 block"
|
className="text-sm font-medium mb-3 block"
|
||||||
>
|
>
|
||||||
Model Name
|
Display Name
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
id="model-name"
|
id="display-name"
|
||||||
value={modelName}
|
value={displayName}
|
||||||
onChange={(e) => handleModelNameChange(e.target.value)}
|
onChange={(e) => handleDisplayNameChange(e.target.value)}
|
||||||
placeholder="Enter model name"
|
placeholder="Enter display name"
|
||||||
className="w-full"
|
className="w-full"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
|
<p className="text-xs text-main-view-fg/60 mt-1">
|
||||||
|
This is the name that will be shown in the interface. The original model file remains unchanged.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Warning Banner */}
|
{/* Warning Banner */}
|
||||||
|
|||||||
@ -104,6 +104,7 @@ export const useModelProvider = create<ModelProviderState>()(
|
|||||||
...model,
|
...model,
|
||||||
settings: settings,
|
settings: settings,
|
||||||
capabilities: existingModel?.capabilities || model.capabilities,
|
capabilities: existingModel?.capabilities || model.capabilities,
|
||||||
|
displayName: existingModel?.displayName || model.displayName,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,6 @@ export function cn(...inputs: ClassValue[]) {
|
|||||||
return twMerge(clsx(inputs))
|
return twMerge(clsx(inputs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function basenameNoExt(filePath: string): string {
|
export function basenameNoExt(filePath: string): string {
|
||||||
const base = path.basename(filePath);
|
const base = path.basename(filePath);
|
||||||
const VALID_EXTENSIONS = [".tar.gz", ".zip"];
|
const VALID_EXTENSIONS = [".tar.gz", ".zip"];
|
||||||
@ -23,6 +22,13 @@ export function basenameNoExt(filePath: string): string {
|
|||||||
return base.slice(0, -path.extname(base).length);
|
return base.slice(0, -path.extname(base).length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the display name for a model, falling back to the model ID if no display name is set
|
||||||
|
*/
|
||||||
|
export function getModelDisplayName(model: Model): string {
|
||||||
|
return model.displayName || model.id
|
||||||
|
}
|
||||||
|
|
||||||
export function getProviderLogo(provider: string) {
|
export function getProviderLogo(provider: string) {
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
case 'jan':
|
case 'jan':
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { Card, CardItem } from '@/containers/Card'
|
|||||||
import HeaderPage from '@/containers/HeaderPage'
|
import HeaderPage from '@/containers/HeaderPage'
|
||||||
import SettingsMenu from '@/containers/SettingsMenu'
|
import SettingsMenu from '@/containers/SettingsMenu'
|
||||||
import { useModelProvider } from '@/hooks/useModelProvider'
|
import { useModelProvider } from '@/hooks/useModelProvider'
|
||||||
import { cn, getProviderTitle } from '@/lib/utils'
|
import { cn, getProviderTitle, getModelDisplayName } from '@/lib/utils'
|
||||||
import {
|
import {
|
||||||
createFileRoute,
|
createFileRoute,
|
||||||
Link,
|
Link,
|
||||||
@ -777,7 +777,7 @@ function ProviderDetail() {
|
|||||||
className="font-medium line-clamp-1"
|
className="font-medium line-clamp-1"
|
||||||
title={model.id}
|
title={model.id}
|
||||||
>
|
>
|
||||||
{model.id}
|
{getModelDisplayName(model)}
|
||||||
</h1>
|
</h1>
|
||||||
<Capabilities capabilities={capabilities} />
|
<Capabilities capabilities={capabilities} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -163,15 +163,14 @@ export class DefaultModelsService implements ModelsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateModel(modelId: string, model: Partial<CoreModel>): Promise<void> {
|
async updateModel(modelId: string, model: Partial<CoreModel>): Promise<void> {
|
||||||
if (model.settings)
|
if (model.settings) {
|
||||||
this.getEngine()?.updateSettings(
|
this.getEngine()?.updateSettings(
|
||||||
model.settings as SettingComponentProps[]
|
model.settings as SettingComponentProps[]
|
||||||
)
|
)
|
||||||
if (modelId !== model.id) {
|
|
||||||
await this.getEngine()
|
|
||||||
?.update(modelId, model)
|
|
||||||
.then(() => console.log('Model updated successfully'))
|
|
||||||
}
|
}
|
||||||
|
// Note: Model name/ID updates are handled at the provider level in the frontend
|
||||||
|
// The engine doesn't have an update method for model metadata
|
||||||
|
console.log('Model update request processed for modelId:', modelId)
|
||||||
}
|
}
|
||||||
|
|
||||||
async pullModel(
|
async pullModel(
|
||||||
|
|||||||
1
web-app/src/types/modelProviders.d.ts
vendored
1
web-app/src/types/modelProviders.d.ts
vendored
@ -28,6 +28,7 @@ type Model = {
|
|||||||
id: string
|
id: string
|
||||||
model?: string
|
model?: string
|
||||||
name?: string
|
name?: string
|
||||||
|
displayName?: string
|
||||||
version?: number | string
|
version?: number | string
|
||||||
description?: string
|
description?: string
|
||||||
format?: string
|
format?: string
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user