fix: #418 valid model config

This commit is contained in:
yidadaa 2023-04-04 01:05:33 +08:00
parent 7572c99f4d
commit 4e644cfca7
4 changed files with 64 additions and 55 deletions

View File

@ -18,3 +18,12 @@
.avatar {
cursor: pointer;
}
.password-input {
display: flex;
justify-content: flex-end;
.password-eye {
margin-right: 4px;
}
}

View File

@ -21,6 +21,7 @@ import {
ALL_MODELS,
useUpdateStore,
useAccessStore,
ModalConfigValidator,
} from "../store";
import { Avatar } from "./chat";
@ -30,6 +31,7 @@ import Link from "next/link";
import { UPDATE_URL } from "../constant";
import { SearchService, usePromptStore } from "../store/prompt";
import { requestUsage } from "../requests";
import { ErrorBoundary } from "./error";
function SettingItem(props: {
title: string;
@ -57,17 +59,14 @@ function PasswordInput(props: HTMLProps<HTMLInputElement>) {
}
return (
<span style={{ display: "flex", justifyContent: "end" }}>
<input
{...props}
style={{ minWidth: "150px" }}
type={visible ? "text" : "password"}
/>
<div className={styles["password-input"]}>
<IconButton
icon={visible ? <EyeIcon /> : <EyeOffIcon />}
onClick={changeVisibility}
className={styles["password-eye"]}
/>
</span>
<input {...props} type={visible ? "text" : "password"} />
</div>
);
}
@ -115,11 +114,13 @@ export function Settings(props: { closeSettings: () => void }) {
useEffect(() => {
checkUpdate();
checkUsage();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const accessStore = useAccessStore();
const enabledAccessControl = useMemo(
() => accessStore.enabledAccessControl(),
// eslint-disable-next-line react-hooks/exhaustive-deps
[],
);
@ -135,7 +136,7 @@ export function Settings(props: { closeSettings: () => void }) {
}, [showUsage]);
return (
<>
<ErrorBoundary>
<div className={styles["window-header"]}>
<div className={styles["window-header-title"]}>
<div className={styles["window-header-main-title"]}>
@ -453,7 +454,9 @@ export function Settings(props: { closeSettings: () => void }) {
onChange={(e) => {
updateConfig(
(config) =>
(config.modelConfig.model = e.currentTarget.value),
(config.modelConfig.model = ModalConfigValidator.model(
e.currentTarget.value,
)),
);
}}
>
@ -470,7 +473,7 @@ export function Settings(props: { closeSettings: () => void }) {
>
<input
type="range"
value={config.modelConfig.temperature.toFixed(1)}
value={config.modelConfig.temperature?.toFixed(1)}
min="0"
max="2"
step="0.1"
@ -478,7 +481,9 @@ export function Settings(props: { closeSettings: () => void }) {
updateConfig(
(config) =>
(config.modelConfig.temperature =
e.currentTarget.valueAsNumber),
ModalConfigValidator.temperature(
e.currentTarget.valueAsNumber,
)),
);
}}
></input>
@ -490,13 +495,15 @@ export function Settings(props: { closeSettings: () => void }) {
<input
type="number"
min={100}
max={4096}
max={32000}
value={config.modelConfig.max_tokens}
onChange={(e) =>
updateConfig(
(config) =>
(config.modelConfig.max_tokens =
e.currentTarget.valueAsNumber),
ModalConfigValidator.max_tokens(
e.currentTarget.valueAsNumber,
)),
)
}
></input>
@ -507,7 +514,7 @@ export function Settings(props: { closeSettings: () => void }) {
>
<input
type="range"
value={config.modelConfig.presence_penalty.toFixed(1)}
value={config.modelConfig.presence_penalty?.toFixed(1)}
min="-2"
max="2"
step="0.5"
@ -515,13 +522,15 @@ export function Settings(props: { closeSettings: () => void }) {
updateConfig(
(config) =>
(config.modelConfig.presence_penalty =
e.currentTarget.valueAsNumber),
ModalConfigValidator.presence_penalty(
e.currentTarget.valueAsNumber,
)),
);
}}
></input>
</SettingItem>
</List>
</div>
</>
</ErrorBoundary>
);
}

View File

@ -1,5 +1,5 @@
import type { ChatRequest, ChatReponse } from "./api/openai/typing";
import { filterConfig, Message, ModelConfig, useAccessStore } from "./store";
import { Message, ModelConfig, useAccessStore } from "./store";
import Locale from "./locales";
import { showToast } from "./components/ui-lib";
@ -123,11 +123,6 @@ export async function requestChatStream(
filterBot: options?.filterBot,
});
// valid and assign model config
if (options?.modelConfig) {
Object.assign(req, filterConfig(options.modelConfig));
}
console.log("[Request] ", req);
const controller = new AbortController();

View File

@ -85,44 +85,40 @@ export const ALL_MODELS = [
},
];
export function isValidModel(name: string) {
return ALL_MODELS.some((m) => m.name === name && m.available);
export function limitNumber(
x: number,
min: number,
max: number,
defaultValue: number,
) {
if (typeof x !== "number" || isNaN(x)) {
return defaultValue;
}
export function isValidNumber(x: number, min: number, max: number) {
return typeof x === "number" && x <= max && x >= min;
return Math.min(max, Math.max(min, x));
}
export function filterConfig(oldConfig: ModelConfig): Partial<ModelConfig> {
const config = Object.assign({}, oldConfig);
export function limitModel(name: string) {
return ALL_MODELS.some((m) => m.name === name && m.available)
? name
: ALL_MODELS[4].name;
}
const validator: {
[k in keyof ModelConfig]: (x: ModelConfig[keyof ModelConfig]) => boolean;
} = {
model(x) {
return isValidModel(x as string);
export const ModalConfigValidator = {
model(x: string) {
return limitModel(x);
},
max_tokens(x) {
return isValidNumber(x as number, 100, 32000);
max_tokens(x: number) {
return limitNumber(x, 0, 32000, 2000);
},
presence_penalty(x) {
return isValidNumber(x as number, -2, 2);
presence_penalty(x: number) {
return limitNumber(x, -2, 2, 0);
},
temperature(x) {
return isValidNumber(x as number, 0, 2);
temperature(x: number) {
return limitNumber(x, 0, 2, 1);
},
};
Object.keys(validator).forEach((k) => {
const key = k as keyof ModelConfig;
if (!validator[key](config[key])) {
delete config[key];
}
});
return config;
}
const DEFAULT_CONFIG: ChatConfig = {
historyMessageCount: 4,
compressMessageLengthThreshold: 1000,