fix(SettingsTab): Context slider inconsistent (#10943)

* fix(i18n): standardize "max" translation to indicate unlimited

* feat(SettingsTab): add current context

* feat(settings): show proper "max" label for context count

* fix(settings): simplify contextCount value expression

* feat(settings): make context count editable with number input
This commit is contained in:
George·Dong 2025-10-30 20:15:35 +08:00 committed by GitHub
parent dd8690b592
commit fa2ec69fa9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 54 additions and 16 deletions

View File

@ -19,6 +19,7 @@ export interface EditableNumberProps {
suffix?: string suffix?: string
prefix?: string prefix?: string
align?: 'start' | 'center' | 'end' align?: 'start' | 'center' | 'end'
formatter?: (value: number | null) => string | number
} }
const EditableNumber: FC<EditableNumberProps> = ({ const EditableNumber: FC<EditableNumberProps> = ({
@ -35,7 +36,8 @@ const EditableNumber: FC<EditableNumberProps> = ({
style, style,
className, className,
size = 'middle', size = 'middle',
align = 'end' align = 'end',
formatter
}) => { }) => {
const [isEditing, setIsEditing] = useState(false) const [isEditing, setIsEditing] = useState(false)
const [inputValue, setInputValue] = useState(value) const [inputValue, setInputValue] = useState(value)
@ -89,7 +91,7 @@ const EditableNumber: FC<EditableNumberProps> = ({
changeOnBlur={changeOnBlur} changeOnBlur={changeOnBlur}
/> />
<DisplayText style={style} className={className} $align={align} $isEditing={isEditing}> <DisplayText style={style} className={className} $align={align} $isEditing={isEditing}>
{value ?? placeholder} {formatter ? formatter(value ?? null) : (value ?? placeholder)}
</DisplayText> </DisplayText>
</Container> </Container>
) )

View File

@ -838,7 +838,7 @@
"label": "Context", "label": "Context",
"tip": "The number of previous messages to keep in the context." "tip": "The number of previous messages to keep in the context."
}, },
"max": "Max", "max": "Unlimited",
"max_tokens": { "max_tokens": {
"confirm": "Set max tokens", "confirm": "Set max tokens",
"confirm_content": "Set the maximum number of tokens the model can generate. Need to consider the context limit of the model, otherwise an error will be reported", "confirm_content": "Set the maximum number of tokens the model can generate. Need to consider the context limit of the model, otherwise an error will be reported",
@ -1051,6 +1051,7 @@
"copied": "Copied", "copied": "Copied",
"copy": "Copy", "copy": "Copy",
"copy_failed": "Copy failed", "copy_failed": "Copy failed",
"current": "Current",
"cut": "Cut", "cut": "Cut",
"default": "Default", "default": "Default",
"delete": "Delete", "delete": "Delete",

View File

@ -1051,6 +1051,7 @@
"copied": "已复制", "copied": "已复制",
"copy": "复制", "copy": "复制",
"copy_failed": "复制失败", "copy_failed": "复制失败",
"current": "当前",
"cut": "剪切", "cut": "剪切",
"default": "默认", "default": "默认",
"delete": "删除", "delete": "删除",

View File

@ -838,7 +838,7 @@
"label": "上下文", "label": "上下文",
"tip": "在上下文中保留的前幾則訊息" "tip": "在上下文中保留的前幾則訊息"
}, },
"max": "最大", "max": "不限",
"max_tokens": { "max_tokens": {
"confirm": "設置最大 Token 數", "confirm": "設置最大 Token 數",
"confirm_content": "設置單次交互所用的最大 Token 數,會影響返回結果的長度。要根據模型上下文限制來設定,否則會發生錯誤", "confirm_content": "設置單次交互所用的最大 Token 數,會影響返回結果的長度。要根據模型上下文限制來設定,否則會發生錯誤",
@ -1051,6 +1051,7 @@
"copied": "已複製", "copied": "已複製",
"copy": "複製", "copy": "複製",
"copy_failed": "複製失敗", "copy_failed": "複製失敗",
"current": "当前",
"cut": "剪下", "cut": "剪下",
"default": "預設", "default": "預設",
"delete": "刪除", "delete": "刪除",

View File

@ -1051,6 +1051,7 @@
"copied": "Kopiert", "copied": "Kopiert",
"copy": "Kopieren", "copy": "Kopieren",
"copy_failed": "Kopieren fehlgeschlagen", "copy_failed": "Kopieren fehlgeschlagen",
"current": "Aktuell",
"cut": "Ausschneiden", "cut": "Ausschneiden",
"default": "Standard", "default": "Standard",
"delete": "Löschen", "delete": "Löschen",

View File

@ -838,7 +838,7 @@
"label": "Πλήθος ενδιάμεσων", "label": "Πλήθος ενδιάμεσων",
"tip": "Πλήθος των μηνυμάτων που θα παραμείνουν στα ενδιάμεσα, όσο μεγαλύτερο είναι το αριθμός, τόσο μεγαλύτερο είναι το μήκος του ενδιάμεσου και τόσο περισσότερα tokens χρησιμοποιούνται. Συνομιλία συνήθως συνιστάται μεταξύ 5-10" "tip": "Πλήθος των μηνυμάτων που θα παραμείνουν στα ενδιάμεσα, όσο μεγαλύτερο είναι το αριθμός, τόσο μεγαλύτερο είναι το μήκος του ενδιάμεσου και τόσο περισσότερα tokens χρησιμοποιούνται. Συνομιλία συνήθως συνιστάται μεταξύ 5-10"
}, },
"max": "Όχι ορισμένο", "max": "άπειρος",
"max_tokens": { "max_tokens": {
"confirm": "Ενεργοποίηση περιορισμού μήκους μηνύματος", "confirm": "Ενεργοποίηση περιορισμού μήκους μηνύματος",
"confirm_content": "Μετά την ενεργοποίηση του περιορισμού μήκους μηνύματος, ο μέγιστος αριθμός των tokens που χρησιμοποιούνται κάθε φορά, θα επηρεάζει το μήκος της απάντησης. Πρέπει να το ρυθμίζετε βάσει των περιορισμών του πλαισίου του μοντέλου, διαφορετικά θα σφάλλεται.", "confirm_content": "Μετά την ενεργοποίηση του περιορισμού μήκους μηνύματος, ο μέγιστος αριθμός των tokens που χρησιμοποιούνται κάθε φορά, θα επηρεάζει το μήκος της απάντησης. Πρέπει να το ρυθμίζετε βάσει των περιορισμών του πλαισίου του μοντέλου, διαφορετικά θα σφάλλεται.",
@ -1051,6 +1051,7 @@
"copied": "Αντιγράφηκε", "copied": "Αντιγράφηκε",
"copy": "Αντιγραφή", "copy": "Αντιγραφή",
"copy_failed": "Αποτυχία αντιγραφής", "copy_failed": "Αποτυχία αντιγραφής",
"current": "Τρέχων",
"cut": "Κοπή", "cut": "Κοπή",
"default": "Προεπιλογή", "default": "Προεπιλογή",
"delete": "Διαγραφή", "delete": "Διαγραφή",

View File

@ -1051,6 +1051,7 @@
"copied": "Copiado", "copied": "Copiado",
"copy": "Copiar", "copy": "Copiar",
"copy_failed": "Error al copiar", "copy_failed": "Error al copiar",
"current": "Actual",
"cut": "Cortar", "cut": "Cortar",
"default": "Predeterminado", "default": "Predeterminado",
"delete": "Eliminar", "delete": "Eliminar",

View File

@ -1051,6 +1051,7 @@
"copied": "Copié", "copied": "Copié",
"copy": "Copier", "copy": "Copier",
"copy_failed": "Échec de la copie", "copy_failed": "Échec de la copie",
"current": "Actuel",
"cut": "Couper", "cut": "Couper",
"default": "Défaut", "default": "Défaut",
"delete": "Supprimer", "delete": "Supprimer",

View File

@ -838,7 +838,7 @@
"label": "コンテキスト", "label": "コンテキスト",
"tip": "コンテキストに保持する以前のメッセージの数" "tip": "コンテキストに保持する以前のメッセージの数"
}, },
"max": "最大", "max": "制限なし",
"max_tokens": { "max_tokens": {
"confirm": "最大トークン数", "confirm": "最大トークン数",
"confirm_content": "最大トークン数を設定すると、モデルが生成できる最大トークン数が制限されます。これにより、返される結果の長さに影響が出る可能性があります。モデルのコンテキスト制限に基づいて設定する必要があります。そうしないとエラーが発生します", "confirm_content": "最大トークン数を設定すると、モデルが生成できる最大トークン数が制限されます。これにより、返される結果の長さに影響が出る可能性があります。モデルのコンテキスト制限に基づいて設定する必要があります。そうしないとエラーが発生します",
@ -1051,6 +1051,7 @@
"copied": "コピーされました", "copied": "コピーされました",
"copy": "コピー", "copy": "コピー",
"copy_failed": "コピーに失敗しました", "copy_failed": "コピーに失敗しました",
"current": "現在",
"cut": "切り取り", "cut": "切り取り",
"default": "デフォルト", "default": "デフォルト",
"delete": "削除", "delete": "削除",

View File

@ -1051,6 +1051,7 @@
"copied": "Copiado", "copied": "Copiado",
"copy": "Copiar", "copy": "Copiar",
"copy_failed": "Falha ao copiar", "copy_failed": "Falha ao copiar",
"current": "Atual",
"cut": "Cortar", "cut": "Cortar",
"default": "Padrão", "default": "Padrão",
"delete": "Excluir", "delete": "Excluir",

View File

@ -838,7 +838,7 @@
"label": "Контекст", "label": "Контекст",
"tip": "Количество предыдущих сообщений, которые нужно сохранить в контексте." "tip": "Количество предыдущих сообщений, которые нужно сохранить в контексте."
}, },
"max": "Максимум", "max": "без ограничений",
"max_tokens": { "max_tokens": {
"confirm": "Максимальное количество токенов", "confirm": "Максимальное количество токенов",
"confirm_content": "Установить максимальное количество токенов, влияет на длину результата. Нужно учитывать контекст модели, иначе будет ошибка", "confirm_content": "Установить максимальное количество токенов, влияет на длину результата. Нужно учитывать контекст модели, иначе будет ошибка",
@ -1051,6 +1051,7 @@
"copied": "Скопировано", "copied": "Скопировано",
"copy": "Копировать", "copy": "Копировать",
"copy_failed": "Не удалось скопировать", "copy_failed": "Не удалось скопировать",
"current": "Текущий",
"cut": "Вырезать", "cut": "Вырезать",
"default": "По умолчанию", "default": "По умолчанию",
"delete": "Удалить", "delete": "Удалить",

View File

@ -3,7 +3,12 @@ import { HStack } from '@renderer/components/Layout'
import Scrollbar from '@renderer/components/Scrollbar' import Scrollbar from '@renderer/components/Scrollbar'
import Selector from '@renderer/components/Selector' import Selector from '@renderer/components/Selector'
import { HelpTooltip } from '@renderer/components/TooltipIcons' import { HelpTooltip } from '@renderer/components/TooltipIcons'
import { DEFAULT_CONTEXTCOUNT, DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE } from '@renderer/config/constant' import {
DEFAULT_CONTEXTCOUNT,
DEFAULT_MAX_TOKENS,
DEFAULT_TEMPERATURE,
MAX_CONTEXT_COUNT
} from '@renderer/config/constant'
import { isOpenAIModel } from '@renderer/config/models' import { isOpenAIModel } from '@renderer/config/models'
import { UNKNOWN } from '@renderer/config/translate' import { UNKNOWN } from '@renderer/config/translate'
import { useCodeStyle } from '@renderer/context/CodeStyleProvider' import { useCodeStyle } from '@renderer/context/CodeStyleProvider'
@ -172,9 +177,6 @@ const SettingsTab: FC<Props> = (props) => {
setStreamOutput(assistant?.settings?.streamOutput ?? true) setStreamOutput(assistant?.settings?.streamOutput ?? true)
}, [assistant]) }, [assistant])
const assistantContextCount = assistant?.settings?.contextCount || 20
const maxContextCount = assistantContextCount > 20 ? assistantContextCount : 20
const model = assistant.model || getDefaultModel() const model = assistant.model || getDefaultModel()
const isOpenAI = isOpenAIModel(model) const isOpenAI = isOpenAIModel(model)
@ -227,21 +229,44 @@ const SettingsTab: FC<Props> = (props) => {
) : ( ) : (
<SettingDivider /> <SettingDivider />
)} )}
<Row align="middle"> <Row align="middle" gutter={10} justify="space-between">
<SettingRowTitleSmall> <SettingRowTitleSmall>
{t('chat.settings.context_count.label')} {t('chat.settings.context_count.label')}
<HelpTooltip title={t('chat.settings.context_count.tip')} /> <HelpTooltip title={t('chat.settings.context_count.tip')} />
</SettingRowTitleSmall> </SettingRowTitleSmall>
<Col span={8}>
<EditableNumber
min={0}
max={20}
step={1}
value={contextCount}
changeOnBlur
onChange={(value) => {
if (value !== null && value >= 0 && value <= 20) {
setContextCount(value)
onContextCountChange(value)
}
}}
formatter={(value) => (value === MAX_CONTEXT_COUNT ? t('chat.settings.max') : (value ?? ''))}
style={{ width: '100%' }}
/>
</Col>
</Row> </Row>
<Row align="middle" gutter={10}> <Row align="middle" gutter={10}>
<Col span={23}> <Col span={24}>
<Slider <Slider
min={0} min={0}
max={maxContextCount} max={20}
onChange={setContextCount} onChange={setContextCount}
onChangeComplete={onContextCountChange} onChangeComplete={onContextCountChange}
value={typeof contextCount === 'number' ? contextCount : 0} value={Math.min(contextCount, 20)}
tooltip={{ open: false }}
step={1} step={1}
marks={{
0: '0',
10: '10',
20: '20'
}}
/> />
</Col> </Col>
</Row> </Row>

View File

@ -359,6 +359,7 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
setTimeoutTimer('contextCount_onChange', () => updateAssistantSettings({ contextCount: value }), 500) setTimeoutTimer('contextCount_onChange', () => updateAssistantSettings({ contextCount: value }), 500)
} }
}} }}
formatter={(value) => (value === MAX_CONTEXT_COUNT ? t('chat.settings.max') : (value ?? ''))}
style={{ width: '100%' }} style={{ width: '100%' }}
/> />
</Col> </Col>
@ -373,7 +374,7 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
value={typeof contextCount === 'number' ? contextCount : 0} value={typeof contextCount === 'number' ? contextCount : 0}
marks={{ 0: '0', 25: '25', 50: '50', 75: '75', 100: t('chat.settings.max') }} marks={{ 0: '0', 25: '25', 50: '50', 75: '75', 100: t('chat.settings.max') }}
step={1} step={1}
tooltip={{ formatter: formatSliderTooltip }} tooltip={{ formatter: formatSliderTooltip, open: false }}
/> />
</Col> </Col>
</Row> </Row>