feat: jinja template customize per model instead provider level (#6053)

This commit is contained in:
Faisal Amir 2025-08-05 21:21:41 +07:00 committed by Ramon Perez
parent dcffa4fa0a
commit 026b21f779
4 changed files with 71 additions and 19 deletions

View File

@ -25,18 +25,6 @@
"controllerType": "checkbox", "controllerType": "checkbox",
"controllerProps": { "value": true } "controllerProps": { "value": true }
}, },
{
"key": "chat_template",
"title": "Custom Jinja Chat template",
"description": "Custom Jinja chat_template to be used for the model",
"controllerType": "input",
"controllerProps": {
"value": "",
"placeholder": "e.g., {% for message in messages %}...{% endfor %} (default is read from GGUF)",
"type": "text",
"textAlign": "right"
}
},
{ {
"key": "threads", "key": "threads",
"title": "Threads", "title": "Threads",

View File

@ -71,7 +71,7 @@ export function ModelSetting({
}) })
// Call debounced stopModel only when updating ctx_len or ngl // Call debounced stopModel only when updating ctx_len or ngl
if (key === 'ctx_len' || key === 'ngl') { if (key === 'ctx_len' || key === 'ngl' || key === 'chat_template') {
debouncedStopModel(model.id) debouncedStopModel(model.id)
} }
} }
@ -101,9 +101,15 @@ export function ModelSetting({
<div className="px-4 space-y-6"> <div className="px-4 space-y-6">
{Object.entries(model.settings || {}).map(([key, value]) => { {Object.entries(model.settings || {}).map(([key, value]) => {
const config = value as ProviderSetting const config = value as ProviderSetting
return ( return (
<div key={key} className="space-y-2"> <div key={key} className="space-y-2">
<div className="flex items-start justify-between gap-8"> <div
className={cn(
'flex items-start justify-between gap-8',
key === 'chat_template' && 'flex-col gap-1'
)}
>
<div className="space-y-1 mb-2"> <div className="space-y-1 mb-2">
<h3 className="font-medium">{config.title}</h3> <h3 className="font-medium">{config.title}</h3>
<p className="text-main-view-fg/70 text-xs"> <p className="text-main-view-fg/70 text-xs">

View File

@ -2,6 +2,7 @@ import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware' import { persist, createJSONStorage } from 'zustand/middleware'
import { localStorageKey } from '@/constants/localStorage' import { localStorageKey } from '@/constants/localStorage'
import { sep } from '@tauri-apps/api/path' import { sep } from '@tauri-apps/api/path'
import { modelSettings } from '@/lib/predefined'
type ModelProviderState = { type ModelProviderState = {
providers: ModelProvider[] providers: ModelProvider[]
@ -211,7 +212,20 @@ export const useModelProvider = create<ModelProviderState>()(
name: localStorageKey.modelProvider, name: localStorageKey.modelProvider,
storage: createJSONStorage(() => localStorage), storage: createJSONStorage(() => localStorage),
migrate: (persistedState: unknown, version: number) => { migrate: (persistedState: unknown, version: number) => {
const state = persistedState as ModelProviderState const state = persistedState as ModelProviderState & {
providers: Array<
ModelProvider & {
models: Array<
Model & {
settings?: Record<string, unknown> & {
chatTemplate?: string
chat_template?: string
}
}
>
}
>
}
// Migration for cont_batching description update (version 0 -> 1) // Migration for cont_batching description update (version 0 -> 1)
if (version === 0 && state?.providers) { if (version === 0 && state?.providers) {
@ -221,7 +235,8 @@ export const useModelProvider = create<ModelProviderState>()(
if (setting.key === 'cont_batching') { if (setting.key === 'cont_batching') {
return { return {
...setting, ...setting,
description: 'Enable continuous batching (a.k.a dynamic batching) for concurrent requests.' description:
'Enable continuous batching (a.k.a dynamic batching) for concurrent requests.',
} }
} }
return setting return setting
@ -230,9 +245,40 @@ export const useModelProvider = create<ModelProviderState>()(
return provider return provider
}) })
} }
// Migration for chatTemplate key to chat_template (version 1 -> 2)
if (version === 1 && state?.providers) {
state.providers.forEach((provider) => {
if (provider.models) {
provider.models.forEach((model) => {
// Initialize settings if it doesn't exist
if (!model.settings) {
model.settings = {}
}
// Migrate chatTemplate key to chat_template
if (model.settings.chatTemplate) {
model.settings.chat_template = model.settings.chatTemplate
delete model.settings.chatTemplate
}
// Add missing chat_template setting if it doesn't exist
if (!model.settings.chat_template) {
model.settings.chat_template = {
...modelSettings.chatTemplate,
controller_props: {
...modelSettings.chatTemplate.controller_props,
},
}
}
})
}
})
}
return state return state
}, },
version: 1, version: 2,
} }
) )
) )

View File

@ -22,7 +22,6 @@ export const modelSettings = {
type: 'number', type: 'number',
}, },
}, },
temperature: { temperature: {
key: 'temperature', key: 'temperature',
title: 'Temperature', title: 'Temperature',
@ -121,4 +120,17 @@ export const modelSettings = {
type: 'number', type: 'number',
}, },
}, },
chatTemplate: {
key: 'chat_template',
title: 'Custom Jinja Chat template',
description: 'Custom Jinja chat_template to be used for the model',
controller_type: 'textarea',
controller_props: {
value: '',
placeholder:
'e.g., {% for message in messages %}...{% endfor %} (default is read from GGUF)',
type: 'text',
textAlign: 'right',
},
},
} }