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",
"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",
"title": "Threads",

View File

@ -71,7 +71,7 @@ export function ModelSetting({
})
// 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)
}
}
@ -101,9 +101,15 @@ export function ModelSetting({
<div className="px-4 space-y-6">
{Object.entries(model.settings || {}).map(([key, value]) => {
const config = value as ProviderSetting
return (
<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">
<h3 className="font-medium">{config.title}</h3>
<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 { localStorageKey } from '@/constants/localStorage'
import { sep } from '@tauri-apps/api/path'
import { modelSettings } from '@/lib/predefined'
type ModelProviderState = {
providers: ModelProvider[]
@ -211,8 +212,21 @@ export const useModelProvider = create<ModelProviderState>()(
name: localStorageKey.modelProvider,
storage: createJSONStorage(() => localStorage),
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)
if (version === 0 && state?.providers) {
state.providers = state.providers.map((provider) => {
@ -221,7 +235,8 @@ export const useModelProvider = create<ModelProviderState>()(
if (setting.key === 'cont_batching') {
return {
...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
@ -230,9 +245,40 @@ export const useModelProvider = create<ModelProviderState>()(
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
},
version: 1,
version: 2,
}
)
)

View File

@ -22,7 +22,6 @@ export const modelSettings = {
type: 'number',
},
},
temperature: {
key: 'temperature',
title: 'Temperature',
@ -121,4 +120,17 @@ export const modelSettings = {
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',
},
},
}