server : (webui) fix numeric settings being saved as string (#11739)
* server : (webui) fix numeric settings being saved as string * add some more comments
This commit is contained in:
parent
d2fe216fb2
commit
0cf867160c
3 changed files with 53 additions and 37 deletions
Binary file not shown.
|
@ -23,6 +23,7 @@ export default function MarkdownDisplay({ content }: { content: string }) {
|
||||||
button: (props) => (
|
button: (props) => (
|
||||||
<CopyCodeButton {...props} origContent={preprocessedContent} />
|
<CopyCodeButton {...props} origContent={preprocessedContent} />
|
||||||
),
|
),
|
||||||
|
// note: do not use "pre", "p" or other basic html elements here, it will cause the node to re-render when the message is being generated (this should be a bug with react-markdown, not sure how to fix it)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{preprocessedContent}
|
{preprocessedContent}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { useAppContext } from '../utils/app.context';
|
||||||
import { CONFIG_DEFAULT, CONFIG_INFO } from '../Config';
|
import { CONFIG_DEFAULT, CONFIG_INFO } from '../Config';
|
||||||
import { isDev } from '../Config';
|
import { isDev } from '../Config';
|
||||||
import StorageUtils from '../utils/storage';
|
import StorageUtils from '../utils/storage';
|
||||||
|
import { isBoolean, isNumeric, isString } from '../utils/misc';
|
||||||
|
|
||||||
type SettKey = keyof typeof CONFIG_DEFAULT;
|
type SettKey = keyof typeof CONFIG_DEFAULT;
|
||||||
|
|
||||||
|
@ -52,7 +53,42 @@ export default function SettingDialog({
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
saveConfig(localConfig);
|
// copy the local config to prevent direct mutation
|
||||||
|
const newConfig: typeof CONFIG_DEFAULT = JSON.parse(
|
||||||
|
JSON.stringify(localConfig)
|
||||||
|
);
|
||||||
|
// validate the config
|
||||||
|
for (const key in newConfig) {
|
||||||
|
const value = newConfig[key as SettKey];
|
||||||
|
const mustBeBoolean = isBoolean(CONFIG_DEFAULT[key as SettKey]);
|
||||||
|
const mustBeString = isString(CONFIG_DEFAULT[key as SettKey]);
|
||||||
|
const mustBeNumeric = isNumeric(CONFIG_DEFAULT[key as SettKey]);
|
||||||
|
if (mustBeString) {
|
||||||
|
if (!isString(value)) {
|
||||||
|
alert(`Value for ${key} must be string`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (mustBeNumeric) {
|
||||||
|
const trimedValue = value.toString().trim();
|
||||||
|
const numVal = Number(trimedValue);
|
||||||
|
if (isNaN(numVal) || !isNumeric(numVal) || trimedValue.length === 0) {
|
||||||
|
alert(`Value for ${key} must be numeric`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// force conversion to number
|
||||||
|
// @ts-expect-error this is safe
|
||||||
|
newConfig[key] = numVal;
|
||||||
|
} else if (mustBeBoolean) {
|
||||||
|
if (!isBoolean(value)) {
|
||||||
|
alert(`Value for ${key} must be boolean`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error(`Unknown default type for key ${key}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isDev) console.log('Saving config', newConfig);
|
||||||
|
saveConfig(newConfig);
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,6 +102,11 @@ export default function SettingDialog({
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onChange = (key: SettKey) => (value: string | boolean) => {
|
||||||
|
// note: we do not perform validation here, because we may get incomplete value as user is still typing it
|
||||||
|
setLocalConfig({ ...localConfig, [key]: value });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<dialog className={`modal ${show ? 'modal-open' : ''}`}>
|
<dialog className={`modal ${show ? 'modal-open' : ''}`}>
|
||||||
<div className="modal-box">
|
<div className="modal-box">
|
||||||
|
@ -79,9 +120,7 @@ export default function SettingDialog({
|
||||||
configKey="apiKey"
|
configKey="apiKey"
|
||||||
configDefault={CONFIG_DEFAULT}
|
configDefault={CONFIG_DEFAULT}
|
||||||
value={localConfig.apiKey}
|
value={localConfig.apiKey}
|
||||||
onChange={(value) =>
|
onChange={onChange('apiKey')}
|
||||||
setLocalConfig({ ...localConfig, apiKey: value })
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<label className="form-control mb-2">
|
<label className="form-control mb-2">
|
||||||
|
@ -92,12 +131,7 @@ export default function SettingDialog({
|
||||||
className="textarea textarea-bordered h-24"
|
className="textarea textarea-bordered h-24"
|
||||||
placeholder={`Default: ${CONFIG_DEFAULT.systemMessage}`}
|
placeholder={`Default: ${CONFIG_DEFAULT.systemMessage}`}
|
||||||
value={localConfig.systemMessage}
|
value={localConfig.systemMessage}
|
||||||
onChange={(e) =>
|
onChange={(e) => onChange('systemMessage')(e.target.value)}
|
||||||
setLocalConfig({
|
|
||||||
...localConfig,
|
|
||||||
systemMessage: e.target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
@ -107,9 +141,7 @@ export default function SettingDialog({
|
||||||
configKey={key}
|
configKey={key}
|
||||||
configDefault={CONFIG_DEFAULT}
|
configDefault={CONFIG_DEFAULT}
|
||||||
value={localConfig[key]}
|
value={localConfig[key]}
|
||||||
onChange={(value) =>
|
onChange={onChange(key)}
|
||||||
setLocalConfig({ ...localConfig, [key]: value })
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
@ -123,9 +155,7 @@ export default function SettingDialog({
|
||||||
configKey="samplers"
|
configKey="samplers"
|
||||||
configDefault={CONFIG_DEFAULT}
|
configDefault={CONFIG_DEFAULT}
|
||||||
value={localConfig.samplers}
|
value={localConfig.samplers}
|
||||||
onChange={(value) =>
|
onChange={onChange('samplers')}
|
||||||
setLocalConfig({ ...localConfig, samplers: value })
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
{OTHER_SAMPLER_KEYS.map((key) => (
|
{OTHER_SAMPLER_KEYS.map((key) => (
|
||||||
<SettingsModalShortInput
|
<SettingsModalShortInput
|
||||||
|
@ -133,9 +163,7 @@ export default function SettingDialog({
|
||||||
configKey={key}
|
configKey={key}
|
||||||
configDefault={CONFIG_DEFAULT}
|
configDefault={CONFIG_DEFAULT}
|
||||||
value={localConfig[key]}
|
value={localConfig[key]}
|
||||||
onChange={(value) =>
|
onChange={onChange(key)}
|
||||||
setLocalConfig({ ...localConfig, [key]: value })
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -152,9 +180,7 @@ export default function SettingDialog({
|
||||||
configKey={key}
|
configKey={key}
|
||||||
configDefault={CONFIG_DEFAULT}
|
configDefault={CONFIG_DEFAULT}
|
||||||
value={localConfig[key]}
|
value={localConfig[key]}
|
||||||
onChange={(value) =>
|
onChange={onChange(key)}
|
||||||
setLocalConfig({ ...localConfig, [key]: value })
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -171,10 +197,7 @@ export default function SettingDialog({
|
||||||
className="checkbox"
|
className="checkbox"
|
||||||
checked={localConfig.showThoughtInProgress}
|
checked={localConfig.showThoughtInProgress}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setLocalConfig({
|
onChange('showThoughtInProgress')(e.target.checked)
|
||||||
...localConfig,
|
|
||||||
showThoughtInProgress: e.target.checked,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<span className="ml-4">
|
<span className="ml-4">
|
||||||
|
@ -187,10 +210,7 @@ export default function SettingDialog({
|
||||||
className="checkbox"
|
className="checkbox"
|
||||||
checked={localConfig.excludeThoughtOnReq}
|
checked={localConfig.excludeThoughtOnReq}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setLocalConfig({
|
onChange('excludeThoughtOnReq')(e.target.checked)
|
||||||
...localConfig,
|
|
||||||
excludeThoughtOnReq: e.target.checked,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<span className="ml-4">
|
<span className="ml-4">
|
||||||
|
@ -220,10 +240,7 @@ export default function SettingDialog({
|
||||||
className="checkbox"
|
className="checkbox"
|
||||||
checked={localConfig.showTokensPerSecond}
|
checked={localConfig.showTokensPerSecond}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setLocalConfig({
|
onChange('showTokensPerSecond')(e.target.checked)
|
||||||
...localConfig,
|
|
||||||
showTokensPerSecond: e.target.checked,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<span className="ml-4">Show tokens per second</span>
|
<span className="ml-4">Show tokens per second</span>
|
||||||
|
@ -245,9 +262,7 @@ export default function SettingDialog({
|
||||||
className="textarea textarea-bordered h-24"
|
className="textarea textarea-bordered h-24"
|
||||||
placeholder='Example: { "mirostat": 1, "min_p": 0.1 }'
|
placeholder='Example: { "mirostat": 1, "min_p": 0.1 }'
|
||||||
value={localConfig.custom}
|
value={localConfig.custom}
|
||||||
onChange={(e) =>
|
onChange={(e) => onChange('custom')(e.target.value)}
|
||||||
setLocalConfig({ ...localConfig, custom: e.target.value })
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue