Skip to content

Commit

Permalink
feat: 添加自定义API参数功能 (#564)
Browse files Browse the repository at this point in the history
* add custom api parameters

* allow more data types for custom api parameters

* pass parameter to api payload

* add custom parameter settings to sidebar

* remove unnecessary object and array types

* extract API custom parameter method to BaseProvider

* add i18n for custom parameter settings

---------

Co-authored-by: 亢奋猫 <[email protected]>
  • Loading branch information
n2yt584v2t4nh7y and kangfenmao authored Dec 29, 2024
1 parent e7545c5 commit ed49066
Show file tree
Hide file tree
Showing 13 changed files with 301 additions and 15 deletions.
10 changes: 9 additions & 1 deletion src/renderer/src/i18n/locales/en-us.json
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,15 @@
"embedding": "Embedding",
"embedding_model": "Embedding Model",
"embedding_model_tooltip": "Add in Settings->Model Provider->Manage",
"dimensions": "Dimensions {{dimensions}}"
"dimensions": "Dimensions {{dimensions}}",
"custom_parameters": "Custom Parameters",
"add_parameter": "Add Parameter",
"parameter_name": "Parameter Name",
"parameter_type": {
"string": "Text",
"number": "Number",
"boolean": "Boolean"
}
},
"prompts": {
"summarize": "You are an assistant who is good at conversation. You need to summarize the user's conversation into a title of 10 characters or less, ensuring it matches the user's primary language without using punctuation or other special symbols."
Expand Down
11 changes: 10 additions & 1 deletion src/renderer/src/i18n/locales/ja-jp.json
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,16 @@
"free": "無料モデル",
"embedding": "埋め込みモデル",
"embedding_model": "埋め込みモデル",
"embedding_model_tooltip": "設定->モデルサービス->管理で追加"
"embedding_model_tooltip": "設定->モデルサービス->管理で追加",
"dimensions": "{{dimensions}} 次元",
"custom_parameters": "カスタムパラメータ",
"add_parameter": "パラメータを追加",
"parameter_name": "パラメータ名",
"parameter_type": {
"string": "テキスト",
"number": "数値",
"boolean": "真偽値"
}
},
"prompts": {
"summarize": "あなたは会話を得意とするアシスタントです。ユーザーの会話を10文字以内のタイトルに要約し、ユーザーの主言語と一致していることを確認してください。句読点や特殊記号は使用しないでください。"
Expand Down
10 changes: 9 additions & 1 deletion src/renderer/src/i18n/locales/ru-ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,15 @@
"embedding": "Встраиваемые модели",
"embedding_model": "Встраиваемые модели",
"embedding_model_tooltip": "Добавьте в настройки->модель сервиса->управление",
"dimensions": "{{dimensions}} мер"
"dimensions": "{{dimensions}} мер",
"custom_parameters": "Пользовательские параметры",
"add_parameter": "Добавить параметр",
"parameter_name": "Имя параметра",
"parameter_type": {
"string": "Текст",
"number": "Число",
"boolean": "Логическое"
}
},
"prompts": {
"summarize": "Вы - эксперт в общении, который суммирует разговоры пользователя в 10-символьном заголовке, совпадающем с языком пользователя, без использования знаков препинания и других специальных символов"
Expand Down
10 changes: 9 additions & 1 deletion src/renderer/src/i18n/locales/zh-cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,15 @@
"embedding": "嵌入模型",
"embedding_model": "嵌入模型",
"embedding_model_tooltip": "在设置->模型服务中点击管理按钮添加",
"dimensions": "{{dimensions}} 维"
"dimensions": "{{dimensions}} 维",
"custom_parameters": "自定义参数",
"add_parameter": "添加参数",
"parameter_name": "参数名称",
"parameter_type": {
"string": "文本",
"number": "数字",
"boolean": "布尔值"
}
},
"prompts": {
"summarize": "你是一名擅长会话的助理,你需要将用户的会话总结为 10 个字以内的标题,标题语言与用户的首要语言一致,不要使用标点符号和其他特殊符号"
Expand Down
10 changes: 9 additions & 1 deletion src/renderer/src/i18n/locales/zh-tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,15 @@
"embedding": "嵌入模型",
"embedding_model": "嵌入模型",
"embedding_model_tooltip": "在设置->模型服务中点击管理按钮添加",
"dimensions": "{{dimensions}} 維"
"dimensions": "{{dimensions}} 維",
"custom_parameters": "自定義參數",
"add_parameter": "添加參數",
"parameter_name": "參數名稱",
"parameter_type": {
"string": "文字",
"number": "數字",
"boolean": "布林值"
}
},
"prompts": {
"summarize": "你是一名擅長會話的助理,你需要將用戶的會話總結為 10 個字以內的標題,標題語言與用戶的首要語言一致,不要使用標點符號和其他特殊符號"
Expand Down
118 changes: 115 additions & 3 deletions src/renderer/src/pages/home/Tabs/SettingsTab.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CheckOutlined, QuestionCircleOutlined, ReloadOutlined } from '@ant-design/icons'
import { CheckOutlined, DeleteOutlined, PlusOutlined, QuestionCircleOutlined, ReloadOutlined } from '@ant-design/icons'
import { HStack } from '@renderer/components/Layout'
import Scrollbar from '@renderer/components/Scrollbar'
import {
Expand Down Expand Up @@ -29,7 +29,7 @@ import {
setShowMessageDivider
} from '@renderer/store/settings'
import { Assistant, AssistantSettings, ThemeMode } from '@renderer/types'
import { Col, InputNumber, Row, Select, Slider, Switch, Tooltip } from 'antd'
import { Button, Col, Input, InputNumber, Row, Select, Slider, Switch, Tooltip } from 'antd'
import { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
Expand Down Expand Up @@ -102,7 +102,8 @@ const SettingsTab: FC<Props> = (props) => {
maxTokens: DEFAULT_MAX_TOKENS,
streamOutput: true,
hideMessages: false,
autoResetModel: false
autoResetModel: false,
customParameters: []
}
})
}
Expand Down Expand Up @@ -202,6 +203,106 @@ const SettingsTab: FC<Props> = (props) => {
/>
</Col>
</Row>
{assistant?.settings?.customParameters?.map((param, index) => (
<ParameterCard key={index}>
<Row align="middle" gutter={8} style={{ marginBottom: 8 }}>
<Col span={14}>
<Input
placeholder={t('models.parameter_name')}
value={param.name}
onChange={(e) => {
const newParams = [...(assistant?.settings?.customParameters || [])]
newParams[index] = { ...param, name: e.target.value }
onUpdateAssistantSettings({ customParameters: newParams })
}}
/>
</Col>
<Col span={10}>
<Select
value={param.type}
onChange={(value: 'string' | 'number' | 'boolean') => {
const newParams = [...(assistant?.settings?.customParameters || [])]
let defaultValue: any = ''
switch (value) {
case 'number':
defaultValue = 0
break
case 'boolean':
defaultValue = false
break
default:
defaultValue = ''
}
newParams[index] = { ...param, type: value, value: defaultValue }
onUpdateAssistantSettings({ customParameters: newParams })
}}
style={{ width: '100%' }}>
<Select.Option value="string">{t('models.parameter_type.string')}</Select.Option>
<Select.Option value="number">{t('models.parameter_type.number')}</Select.Option>
<Select.Option value="boolean">{t('models.parameter_type.boolean')}</Select.Option>
</Select>
</Col>
</Row>
<Row align="middle" gutter={10}>
<Col span={20}>
{param.type === 'boolean' ? (
<Switch
checked={param.value as boolean}
onChange={(checked) => {
const newParams = [...(assistant?.settings?.customParameters || [])]
newParams[index] = { ...param, value: checked }
onUpdateAssistantSettings({ customParameters: newParams })
}}
/>
) : param.type === 'number' ? (
<InputNumber
style={{ width: '100%' }}
value={param.value as number}
onChange={(value) => {
const newParams = [...(assistant?.settings?.customParameters || [])]
newParams[index] = { ...param, value: value || 0 }
onUpdateAssistantSettings({ customParameters: newParams })
}}
step={0.01}
/>
) : (
<Input
value={typeof param.value === 'string' ? param.value : JSON.stringify(param.value)}
onChange={(e) => {
const newParams = [...(assistant?.settings?.customParameters || [])]
newParams[index] = { ...param, value: e.target.value }
onUpdateAssistantSettings({ customParameters: newParams })
}}
/>
)}
</Col>
<Col span={4}>
<Button
icon={<DeleteOutlined />}
onClick={() => {
const newParams = [...(assistant?.settings?.customParameters || [])]
newParams.splice(index, 1)
onUpdateAssistantSettings({ customParameters: newParams })
}}
danger
style={{ width: '100%' }}
/>
</Col>
</Row>
</ParameterCard>
))}
<Button
icon={<PlusOutlined />}
onClick={() => {
const newParams = [
...(assistant?.settings?.customParameters || []),
{ name: '', value: '', type: 'string' as const }
]
onUpdateAssistantSettings({ customParameters: newParams })
}}
style={{ marginBottom: 0, width: '100%', borderStyle: 'dashed' }}>
{t('models.add_parameter')}
</Button>
</SettingGroup>
<SettingGroup>
<SettingSubtitle style={{ marginTop: 0 }}>{t('settings.messages.title')}</SettingSubtitle>
Expand Down Expand Up @@ -418,4 +519,15 @@ export const SettingGroup = styled.div<{ theme?: ThemeMode }>`
background: var(--color-group-background);
`

const ParameterCard = styled.div`
margin-bottom: 8px;
padding: 8px;
border: 1px solid var(--color-border);
border-radius: 6px;
background: var(--color-background);
&:last-child {
margin-bottom: 12px;
}
`

export default SettingsTab
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons'
import { DeleteOutlined, PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons'
import ModelAvatar from '@renderer/components/Avatar/ModelAvatar'
import { HStack } from '@renderer/components/Layout'
import SelectModelPopup from '@renderer/components/Popups/SelectModelPopup'
import { DEFAULT_CONTEXTCOUNT, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
import { SettingRow } from '@renderer/pages/settings'
import { Assistant, AssistantSettings } from '@renderer/types'
import { Button, Col, Divider, InputNumber, Row, Slider, Switch, Tooltip } from 'antd'
import { Button, Col, Divider, Input, InputNumber, Row, Select, Slider, Switch, Tooltip } from 'antd'
import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
Expand All @@ -25,6 +25,13 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
const [streamOutput, setStreamOutput] = useState(assistant?.settings?.streamOutput ?? true)
const [defaultModel, setDefaultModel] = useState(assistant?.defaultModel)
const [topP, setTopP] = useState(assistant?.settings?.topP ?? 1)
const [customParameters, setCustomParameters] = useState<
Array<{
name: string
value: string | number | boolean
type: 'string' | 'number' | 'boolean'
}>
>(assistant?.settings?.customParameters ?? [])
const { t } = useTranslation()

const onTemperatureChange = (value) => {
Expand All @@ -51,20 +58,93 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
}
}

const onAddCustomParameter = () => {
const newParam = { name: '', value: '', type: 'string' as const }
const newParams = [...customParameters, newParam]
setCustomParameters(newParams)
updateAssistantSettings({ customParameters: newParams })
}

const onUpdateCustomParameter = (
index: number,
field: 'name' | 'value' | 'type',
value: string | number | boolean
) => {
const newParams = [...customParameters]
if (field === 'type') {
let defaultValue: any = ''
switch (value) {
case 'number':
defaultValue = 0
break
case 'boolean':
defaultValue = false
break
default:
defaultValue = ''
}
newParams[index] = {
...newParams[index],
type: value as any,
value: defaultValue
}
} else {
newParams[index] = { ...newParams[index], [field]: value }
}
setCustomParameters(newParams)
updateAssistantSettings({ customParameters: newParams })
}

const renderParameterValueInput = (param: (typeof customParameters)[0], index: number) => {
switch (param.type) {
case 'number':
return (
<InputNumber
style={{ width: '100%' }}
value={param.value as number}
onChange={(value) => onUpdateCustomParameter(index, 'value', value || 0)}
step={0.01}
/>
)
case 'boolean':
return (
<Switch
checked={param.value as boolean}
onChange={(checked) => onUpdateCustomParameter(index, 'value', checked)}
/>
)
default:
return (
<Input
value={param.value as string}
onChange={(e) => onUpdateCustomParameter(index, 'value', e.target.value)}
/>
)
}
}

const onDeleteCustomParameter = (index: number) => {
const newParams = customParameters.filter((_, i) => i !== index)
setCustomParameters(newParams)
updateAssistantSettings({ customParameters: newParams })
}

const onReset = () => {
setTemperature(DEFAULT_TEMPERATURE)
setContextCount(DEFAULT_CONTEXTCOUNT)
setEnableMaxTokens(false)
setMaxTokens(0)
setStreamOutput(true)
setTopP(1)
setCustomParameters([])
updateAssistantSettings({
temperature: DEFAULT_TEMPERATURE,
contextCount: DEFAULT_CONTEXTCOUNT,
enableMaxTokens: false,
maxTokens: 0,
streamOutput: true,
topP: 1
topP: 1,
customParameters: []
})
}

Expand Down Expand Up @@ -249,6 +329,38 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
}}
/>
</SettingRow>
<Divider style={{ margin: '10px 0' }} />
<SettingRow style={{ minHeight: 30 }}>
<Label>{t('models.custom_parameters')}</Label>
<Button icon={<PlusOutlined />} onClick={onAddCustomParameter}>
{t('models.add_parameter')}
</Button>
</SettingRow>
{customParameters.map((param, index) => (
<Row key={index} align="middle" gutter={10} style={{ marginTop: 10 }}>
<Col span={6}>
<Input
placeholder={t('models.parameter_name')}
value={param.name}
onChange={(e) => onUpdateCustomParameter(index, 'name', e.target.value)}
/>
</Col>
<Col span={4}>
<Select
value={param.type}
onChange={(value) => onUpdateCustomParameter(index, 'type', value)}
style={{ width: '100%' }}>
<Select.Option value="string">{t('models.parameter_type.string')}</Select.Option>
<Select.Option value="number">{t('models.parameter_type.number')}</Select.Option>
<Select.Option value="boolean">{t('models.parameter_type.boolean')}</Select.Option>
</Select>
</Col>
<Col span={11}>{renderParameterValueInput(param, index)}</Col>
<Col span={3}>
<Button icon={<DeleteOutlined />} onClick={() => onDeleteCustomParameter(index)} danger />
</Col>
</Row>
))}
<Divider style={{ margin: '15px 0' }} />
<HStack justifyContent="flex-end">
<Button onClick={onReset} style={{ width: 80 }} danger type="primary">
Expand Down
Loading

0 comments on commit ed49066

Please sign in to comment.