NextChat-U/app/store/config.ts

263 lines
6.5 KiB
TypeScript
Raw Permalink Normal View History

import { LLMModel } from "../client/api";
2024-12-27 22:52:22 +09:00
import { DalleQuality, DalleStyle, ModelSize } from "../typing";
import { getClientConfig } from "../config/client";
import {
DEFAULT_INPUT_TEMPLATE,
DEFAULT_MODELS,
DEFAULT_SIDEBAR_WIDTH,
2024-08-27 17:21:02 +09:00
DEFAULT_TTS_ENGINE,
DEFAULT_TTS_ENGINES,
DEFAULT_TTS_MODEL,
DEFAULT_TTS_MODELS,
DEFAULT_TTS_VOICE,
DEFAULT_TTS_VOICES,
StoreKey,
2024-07-05 20:59:45 +09:00
ServiceProvider,
realtimeModels,
} from "../constant";
import { createPersistStore } from "../utils/store";
2024-11-07 22:28:23 +09:00
import type { Voice } from "rt-client";
export type ModelType = (typeof DEFAULT_MODELS)[number]["name"];
2024-08-27 17:21:02 +09:00
export type TTSModelType = (typeof DEFAULT_TTS_MODELS)[number];
export type TTSVoiceType = (typeof DEFAULT_TTS_VOICES)[number];
export type TTSEngineType = (typeof DEFAULT_TTS_ENGINES)[number];
2023-04-22 01:12:07 +09:00
export enum SubmitKey {
Enter = "Enter",
CtrlEnter = "Ctrl + Enter",
ShiftEnter = "Shift + Enter",
AltEnter = "Alt + Enter",
MetaEnter = "Meta + Enter",
}
export enum Theme {
Auto = "auto",
Dark = "dark",
Light = "light",
}
const config = getClientConfig();
2023-04-23 02:37:47 +09:00
export const DEFAULT_CONFIG = {
lastUpdate: Date.now(), // timestamp, to merge state
2024-01-25 16:17:16 +09:00
submitKey: SubmitKey.Enter,
2023-04-22 01:12:07 +09:00
avatar: "1f603",
fontSize: 14,
fontFamily: "",
2023-04-22 01:12:07 +09:00
theme: Theme.Auto as Theme,
2024-05-20 20:02:46 +09:00
tightBorder: !!config?.isApp,
sendPreviewBubble: true,
enableAutoGenerateTitle: true,
sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
2023-04-22 01:12:07 +09:00
enableArtifacts: true, // show artifacts config
2024-10-11 20:19:36 +09:00
enableCodeFold: true, // code fold config
2023-04-22 01:12:07 +09:00
disablePromptHint: false,
2024-05-20 20:02:46 +09:00
dontShowMaskSplashScreen: false, // dont show splash screen when create chat
2023-07-05 23:39:25 +09:00
hideBuiltinMasks: false, // dont add builtin masks
customModels: "",
models: DEFAULT_MODELS as any as LLMModel[],
2023-04-22 01:12:07 +09:00
modelConfig: {
model: "gpt-4o-mini" as ModelType,
2024-07-09 13:16:37 +09:00
providerName: "OpenAI" as ServiceProvider,
temperature: 0.5,
2023-07-04 01:39:54 +09:00
top_p: 1,
max_tokens: 4000,
2023-04-22 01:12:07 +09:00
presence_penalty: 0,
frequency_penalty: 0,
2023-04-23 02:27:15 +09:00
sendMemory: true,
historyMessageCount: 4,
2023-04-22 02:13:23 +09:00
compressMessageLengthThreshold: 1000,
2024-10-09 14:49:33 +09:00
compressModel: "",
compressProviderName: "",
enableInjectSystemPrompts: true,
template: config?.template ?? DEFAULT_INPUT_TEMPLATE,
2024-12-27 22:52:22 +09:00
size: "1024x1024" as ModelSize,
quality: "standard" as DalleQuality,
style: "vivid" as DalleStyle,
2023-04-22 01:12:07 +09:00
},
2024-08-27 17:21:02 +09:00
ttsConfig: {
enable: false,
autoplay: false,
engine: DEFAULT_TTS_ENGINE,
model: DEFAULT_TTS_MODEL,
voice: DEFAULT_TTS_VOICE,
speed: 1.0,
},
2024-11-07 22:28:23 +09:00
realtimeConfig: {
enable: false,
provider: "OpenAI" as ServiceProvider,
model: realtimeModels[0], // 修改默认模型为realtimeModels中的第一个模型
apiKey: process.env.OPENAI_API_KEY || "", // 默认读取env的OPENAI_API_KEY
2024-11-07 22:28:23 +09:00
azure: {
endpoint: "",
deployment: "",
},
temperature: 0.9,
voice: "alloy" as Voice,
},
2023-04-22 01:12:07 +09:00
};
export type ChatConfig = typeof DEFAULT_CONFIG;
export type ModelConfig = ChatConfig["modelConfig"];
2024-08-27 17:21:02 +09:00
export type TTSConfig = ChatConfig["ttsConfig"];
2024-11-07 22:28:23 +09:00
export type RealtimeConfig = ChatConfig["realtimeConfig"];
2023-04-22 01:12:07 +09:00
export function limitNumber(
x: number,
min: number,
max: number,
defaultValue: number,
2023-04-22 01:12:07 +09:00
) {
if (isNaN(x)) {
2023-04-22 01:12:07 +09:00
return defaultValue;
}
return Math.min(max, Math.max(min, x));
}
2024-08-27 17:21:02 +09:00
export const TTSConfigValidator = {
engine(x: string) {
return x as TTSEngineType;
},
model(x: string) {
return x as TTSModelType;
},
voice(x: string) {
return x as TTSVoiceType;
},
speed(x: number) {
return limitNumber(x, 0.25, 4.0, 1.0);
},
};
2023-04-22 01:12:07 +09:00
export const ModalConfigValidator = {
model(x: string) {
2023-07-09 22:56:49 +09:00
return x as ModelType;
2023-04-22 01:12:07 +09:00
},
max_tokens(x: number) {
return limitNumber(x, 0, 512000, 1024);
2023-04-22 01:12:07 +09:00
},
presence_penalty(x: number) {
return limitNumber(x, -2, 2, 0);
},
frequency_penalty(x: number) {
return limitNumber(x, -2, 2, 0);
},
2023-04-22 01:12:07 +09:00
temperature(x: number) {
2024-02-20 19:05:17 +09:00
return limitNumber(x, 0, 2, 1);
2023-04-22 01:12:07 +09:00
},
2023-07-04 01:39:54 +09:00
top_p(x: number) {
return limitNumber(x, 0, 1, 1);
},
2023-04-22 01:12:07 +09:00
};
export const useAppConfig = createPersistStore(
{ ...DEFAULT_CONFIG },
(set, get) => ({
reset() {
set(() => ({ ...DEFAULT_CONFIG }));
},
mergeModels(newModels: LLMModel[]) {
if (!newModels || newModels.length === 0) {
return;
}
const oldModels = get().models;
const modelMap: Record<string, LLMModel> = {};
for (const model of oldModels) {
model.available = false;
2024-07-04 17:11:37 +09:00
modelMap[`${model.name}@${model?.provider?.id}`] = model;
}
for (const model of newModels) {
model.available = true;
2024-07-04 17:11:37 +09:00
modelMap[`${model.name}@${model?.provider?.id}`] = model;
}
set(() => ({
models: Object.values(modelMap),
}));
},
allModels() {},
}),
{
name: StoreKey.Config,
version: 4.1,
merge(persistedState, currentState) {
const state = persistedState as ChatConfig | undefined;
if (!state) return { ...currentState };
const models = currentState.models.slice();
state.models.forEach((pModel) => {
const idx = models.findIndex(
(v) => v.name === pModel.name && v.provider === pModel.provider,
);
if (idx !== -1) models[idx] = pModel;
else models.push(pModel);
});
return { ...currentState, ...state, models: models };
},
migrate(persistedState, version) {
const state = persistedState as ChatConfig;
if (version < 3.4) {
state.modelConfig.sendMemory = true;
state.modelConfig.historyMessageCount = 4;
state.modelConfig.compressMessageLengthThreshold = 1000;
state.modelConfig.frequency_penalty = 0;
state.modelConfig.top_p = 1;
state.modelConfig.template = DEFAULT_INPUT_TEMPLATE;
state.dontShowMaskSplashScreen = false;
state.hideBuiltinMasks = false;
}
if (version < 3.5) {
state.customModels = "claude,claude-100k";
}
if (version < 3.6) {
state.modelConfig.enableInjectSystemPrompts = true;
}
if (version < 3.7) {
state.enableAutoGenerateTitle = true;
}
if (version < 3.8) {
state.lastUpdate = Date.now();
}
if (version < 3.9) {
state.modelConfig.template =
state.modelConfig.template !== DEFAULT_INPUT_TEMPLATE
? state.modelConfig.template
: config?.template ?? DEFAULT_INPUT_TEMPLATE;
}
if (version < 4.1) {
state.modelConfig.compressModel =
DEFAULT_CONFIG.modelConfig.compressModel;
state.modelConfig.compressProviderName =
DEFAULT_CONFIG.modelConfig.compressProviderName;
}
return state as any;
},
},
2023-04-22 01:12:07 +09:00
);