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",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tauri-plugin-hardware",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover'
|
||||
import { useModelProvider } from '@/hooks/useModelProvider'
|
||||
import { cn, getProviderTitle } from '@/lib/utils'
|
||||
import { cn, getProviderTitle, getModelDisplayName } from '@/lib/utils'
|
||||
import { highlightFzfMatch } from '@/utils/highlight'
|
||||
import Capabilities from './Capabilities'
|
||||
import { IconSettings, IconX } from '@tabler/icons-react'
|
||||
@ -240,7 +240,7 @@ const DropdownModelProvider = ({
|
||||
// Update display model when selection changes
|
||||
useEffect(() => {
|
||||
if (selectedProvider && selectedModel) {
|
||||
setDisplayModel(selectedModel.id)
|
||||
setDisplayModel(getModelDisplayName(selectedModel))
|
||||
} else {
|
||||
setDisplayModel(t('common:selectAModel'))
|
||||
}
|
||||
@ -326,7 +326,7 @@ const DropdownModelProvider = ({
|
||||
// Create Fzf instance for fuzzy search
|
||||
const fzfInstance = useMemo(() => {
|
||||
return new Fzf(searchableItems, {
|
||||
selector: (item) => item.model.id.toLowerCase(),
|
||||
selector: (item) => `${getModelDisplayName(item.model)} ${item.model.id}`.toLowerCase(),
|
||||
})
|
||||
}, [searchableItems])
|
||||
|
||||
@ -390,7 +390,7 @@ const DropdownModelProvider = ({
|
||||
const handleSelect = useCallback(
|
||||
async (searchableModel: SearchableModel) => {
|
||||
// Immediately update display to prevent double-click issues
|
||||
setDisplayModel(searchableModel.model.id)
|
||||
setDisplayModel(getModelDisplayName(searchableModel.model))
|
||||
setSearchValue('')
|
||||
setOpen(false)
|
||||
|
||||
@ -576,7 +576,7 @@ const DropdownModelProvider = ({
|
||||
/>
|
||||
</div>
|
||||
<span className="text-main-view-fg/80 text-sm">
|
||||
{searchableModel.model.id}
|
||||
{getModelDisplayName(searchableModel.model)}
|
||||
</span>
|
||||
<div className="flex-1"></div>
|
||||
{capabilities.length > 0 && (
|
||||
@ -669,7 +669,7 @@ const DropdownModelProvider = ({
|
||||
className="text-main-view-fg/80 text-sm"
|
||||
title={searchableModel.model.id}
|
||||
>
|
||||
{searchableModel.model.id}
|
||||
{getModelDisplayName(searchableModel.model)}
|
||||
</span>
|
||||
<div className="flex-1"></div>
|
||||
{capabilities.length > 0 && (
|
||||
|
||||
@ -14,7 +14,7 @@ import { Button } from '@/components/ui/button'
|
||||
import { DynamicControllerSetting } from '@/containers/dynamicControllerSetting'
|
||||
import { useModelProvider } from '@/hooks/useModelProvider'
|
||||
import { useServiceHub } from '@/hooks/useServiceHub'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { cn, getModelDisplayName } from '@/lib/utils'
|
||||
import { useTranslation } from '@/i18n/react-i18next-compat'
|
||||
|
||||
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">
|
||||
<SheetHeader>
|
||||
<SheetTitle>
|
||||
{t('common:modelSettings.title', { modelId: model.id })}
|
||||
{t('common:modelSettings.title', { modelId: getModelDisplayName(model) })}
|
||||
</SheetTitle>
|
||||
<SheetDescription>
|
||||
{t('common:modelSettings.description')}
|
||||
|
||||
@ -39,8 +39,8 @@ export const DialogEditModel = ({
|
||||
const { t } = useTranslation()
|
||||
const { updateProvider, setProviders } = useModelProvider()
|
||||
const [selectedModelId, setSelectedModelId] = useState<string>('')
|
||||
const [modelName, setModelName] = useState<string>('')
|
||||
const [originalModelName, setOriginalModelName] = useState<string>('')
|
||||
const [displayName, setDisplayName] = useState<string>('')
|
||||
const [originalDisplayName, setOriginalDisplayName] = useState<string>('')
|
||||
const [originalCapabilities, setOriginalCapabilities] = useState<
|
||||
Record<string, boolean>
|
||||
>({})
|
||||
@ -86,7 +86,7 @@ export const DialogEditModel = ({
|
||||
(m: any) => m.id === selectedModelId
|
||||
)
|
||||
|
||||
// Initialize capabilities and model name from selected model
|
||||
// Initialize capabilities and display name from selected model
|
||||
useEffect(() => {
|
||||
if (selectedModel) {
|
||||
const modelCapabilities = selectedModel.capabilities || []
|
||||
@ -98,9 +98,10 @@ export const DialogEditModel = ({
|
||||
web_search: modelCapabilities.includes('web_search'),
|
||||
reasoning: modelCapabilities.includes('reasoning'),
|
||||
})
|
||||
const modelNameValue = selectedModel.id
|
||||
setModelName(modelNameValue)
|
||||
setOriginalModelName(modelNameValue)
|
||||
// Use existing displayName if available, otherwise fall back to model ID
|
||||
const displayNameValue = (selectedModel as any).displayName || selectedModel.id
|
||||
setDisplayName(displayNameValue)
|
||||
setOriginalDisplayName(displayNameValue)
|
||||
|
||||
const originalCaps = {
|
||||
completion: modelCapabilities.includes('completion'),
|
||||
@ -122,14 +123,14 @@ export const DialogEditModel = ({
|
||||
}))
|
||||
}
|
||||
|
||||
// Handle model name change
|
||||
const handleModelNameChange = (newName: string) => {
|
||||
setModelName(newName)
|
||||
// Handle display name change
|
||||
const handleDisplayNameChange = (newName: string) => {
|
||||
setDisplayName(newName)
|
||||
}
|
||||
|
||||
// Check if there are unsaved changes
|
||||
const hasUnsavedChanges = () => {
|
||||
const nameChanged = modelName !== originalModelName
|
||||
const nameChanged = displayName !== originalDisplayName
|
||||
const capabilitiesChanged =
|
||||
JSON.stringify(capabilities) !== JSON.stringify(originalCapabilities)
|
||||
return nameChanged || capabilitiesChanged
|
||||
@ -141,13 +142,21 @@ export const DialogEditModel = ({
|
||||
|
||||
setIsLoading(true)
|
||||
try {
|
||||
// Update model name if changed
|
||||
if (modelName !== originalModelName) {
|
||||
await serviceHub
|
||||
.models()
|
||||
.updateModel(selectedModel.id, { id: modelName })
|
||||
setOriginalModelName(modelName)
|
||||
await serviceHub.providers().getProviders().then(setProviders)
|
||||
let updatedModels = provider.models
|
||||
|
||||
// Update display name if changed
|
||||
if (displayName !== originalDisplayName) {
|
||||
// Update the model in the provider models array with displayName
|
||||
updatedModels = updatedModels.map((m: any) => {
|
||||
if (m.id === selectedModelId) {
|
||||
return {
|
||||
...m,
|
||||
displayName: displayName,
|
||||
}
|
||||
}
|
||||
return m
|
||||
})
|
||||
setOriginalDisplayName(displayName)
|
||||
}
|
||||
|
||||
// Update capabilities if changed
|
||||
@ -159,8 +168,7 @@ export const DialogEditModel = ({
|
||||
.map(([capName]) => capName)
|
||||
|
||||
// Find and update the model in the provider
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const updatedModels = provider.models.map((m: any) => {
|
||||
updatedModels = updatedModels.map((m: any) => {
|
||||
if (m.id === selectedModelId) {
|
||||
return {
|
||||
...m,
|
||||
@ -172,15 +180,15 @@ export const DialogEditModel = ({
|
||||
return m
|
||||
})
|
||||
|
||||
setOriginalCapabilities(capabilities)
|
||||
}
|
||||
|
||||
// Update the provider with the updated models
|
||||
updateProvider(provider.provider, {
|
||||
...provider,
|
||||
models: updatedModels,
|
||||
})
|
||||
|
||||
setOriginalCapabilities(capabilities)
|
||||
}
|
||||
|
||||
// Show success toast and close dialog
|
||||
toast.success('Model updated successfully')
|
||||
setIsOpen(false)
|
||||
@ -213,22 +221,25 @@ export const DialogEditModel = ({
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
{/* Model Name Section */}
|
||||
{/* Model Display Name Section */}
|
||||
<div className="py-1">
|
||||
<label
|
||||
htmlFor="model-name"
|
||||
htmlFor="display-name"
|
||||
className="text-sm font-medium mb-3 block"
|
||||
>
|
||||
Model Name
|
||||
Display Name
|
||||
</label>
|
||||
<Input
|
||||
id="model-name"
|
||||
value={modelName}
|
||||
onChange={(e) => handleModelNameChange(e.target.value)}
|
||||
placeholder="Enter model name"
|
||||
id="display-name"
|
||||
value={displayName}
|
||||
onChange={(e) => handleDisplayNameChange(e.target.value)}
|
||||
placeholder="Enter display name"
|
||||
className="w-full"
|
||||
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>
|
||||
|
||||
{/* Warning Banner */}
|
||||
|
||||
@ -104,6 +104,7 @@ export const useModelProvider = create<ModelProviderState>()(
|
||||
...model,
|
||||
settings: settings,
|
||||
capabilities: existingModel?.capabilities || model.capabilities,
|
||||
displayName: existingModel?.displayName || model.displayName,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@ -7,7 +7,6 @@ export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
||||
|
||||
export function basenameNoExt(filePath: string): string {
|
||||
const base = path.basename(filePath);
|
||||
const VALID_EXTENSIONS = [".tar.gz", ".zip"];
|
||||
@ -23,6 +22,13 @@ export function basenameNoExt(filePath: string): string {
|
||||
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) {
|
||||
switch (provider) {
|
||||
case 'jan':
|
||||
|
||||
@ -3,7 +3,7 @@ import { Card, CardItem } from '@/containers/Card'
|
||||
import HeaderPage from '@/containers/HeaderPage'
|
||||
import SettingsMenu from '@/containers/SettingsMenu'
|
||||
import { useModelProvider } from '@/hooks/useModelProvider'
|
||||
import { cn, getProviderTitle } from '@/lib/utils'
|
||||
import { cn, getProviderTitle, getModelDisplayName } from '@/lib/utils'
|
||||
import {
|
||||
createFileRoute,
|
||||
Link,
|
||||
@ -777,7 +777,7 @@ function ProviderDetail() {
|
||||
className="font-medium line-clamp-1"
|
||||
title={model.id}
|
||||
>
|
||||
{model.id}
|
||||
{getModelDisplayName(model)}
|
||||
</h1>
|
||||
<Capabilities capabilities={capabilities} />
|
||||
</div>
|
||||
|
||||
@ -163,15 +163,14 @@ export class DefaultModelsService implements ModelsService {
|
||||
}
|
||||
|
||||
async updateModel(modelId: string, model: Partial<CoreModel>): Promise<void> {
|
||||
if (model.settings)
|
||||
if (model.settings) {
|
||||
this.getEngine()?.updateSettings(
|
||||
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(
|
||||
|
||||
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
|
||||
model?: string
|
||||
name?: string
|
||||
displayName?: string
|
||||
version?: number | string
|
||||
description?: string
|
||||
format?: string
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user