mirror of
				https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
				synced 2025-11-04 16:23:41 +08:00 
			
		
		
		
	fix: #963 config not work
This commit is contained in:
		@@ -32,6 +32,7 @@ import {
 | 
			
		||||
  useAccessStore,
 | 
			
		||||
  Theme,
 | 
			
		||||
  ModelType,
 | 
			
		||||
  useAppConfig,
 | 
			
		||||
} from "../store";
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
@@ -69,7 +70,7 @@ const Emoji = dynamic(async () => (await import("emoji-picker-react")).Emoji, {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export function Avatar(props: { role: Message["role"]; model?: ModelType }) {
 | 
			
		||||
  const config = useChatStore((state) => state.config);
 | 
			
		||||
  const config = useAppConfig();
 | 
			
		||||
 | 
			
		||||
  if (props.role !== "user") {
 | 
			
		||||
    return (
 | 
			
		||||
@@ -285,7 +286,7 @@ function PromptToast(props: {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function useSubmitHandler() {
 | 
			
		||||
  const config = useChatStore((state) => state.config);
 | 
			
		||||
  const config = useAppConfig();
 | 
			
		||||
  const submitKey = config.submitKey;
 | 
			
		||||
 | 
			
		||||
  const shouldSubmit = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
 | 
			
		||||
@@ -361,16 +362,16 @@ export function ChatActions(props: {
 | 
			
		||||
  scrollToBottom: () => void;
 | 
			
		||||
  hitBottom: boolean;
 | 
			
		||||
}) {
 | 
			
		||||
  const chatStore = useChatStore();
 | 
			
		||||
  const config = useAppConfig();
 | 
			
		||||
 | 
			
		||||
  // switch themes
 | 
			
		||||
  const theme = chatStore.config.theme;
 | 
			
		||||
  const theme = config.theme;
 | 
			
		||||
  function nextTheme() {
 | 
			
		||||
    const themes = [Theme.Auto, Theme.Light, Theme.Dark];
 | 
			
		||||
    const themeIndex = themes.indexOf(theme);
 | 
			
		||||
    const nextIndex = (themeIndex + 1) % themes.length;
 | 
			
		||||
    const nextTheme = themes[nextIndex];
 | 
			
		||||
    chatStore.updateConfig((config) => (config.theme = nextTheme));
 | 
			
		||||
    config.update((config) => (config.theme = nextTheme));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // stop all responses
 | 
			
		||||
@@ -428,7 +429,8 @@ export function Chat() {
 | 
			
		||||
    state.currentSession(),
 | 
			
		||||
    state.currentSessionIndex,
 | 
			
		||||
  ]);
 | 
			
		||||
  const fontSize = useChatStore((state) => state.config.fontSize);
 | 
			
		||||
  const config = useAppConfig();
 | 
			
		||||
  const fontSize = config.fontSize;
 | 
			
		||||
 | 
			
		||||
  const inputRef = useRef<HTMLTextAreaElement>(null);
 | 
			
		||||
  const [userInput, setUserInput] = useState("");
 | 
			
		||||
@@ -492,7 +494,7 @@ export function Chat() {
 | 
			
		||||
    // clear search results
 | 
			
		||||
    if (n === 0) {
 | 
			
		||||
      setPromptHints([]);
 | 
			
		||||
    } else if (!chatStore.config.disablePromptHint && n < SEARCH_TEXT_LIMIT) {
 | 
			
		||||
    } else if (!config.disablePromptHint && n < SEARCH_TEXT_LIMIT) {
 | 
			
		||||
      // check if need to trigger auto completion
 | 
			
		||||
      if (text.startsWith("/")) {
 | 
			
		||||
        let searchText = text.slice(1);
 | 
			
		||||
@@ -583,8 +585,6 @@ export function Chat() {
 | 
			
		||||
    inputRef.current?.focus();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const config = useChatStore((state) => state.config);
 | 
			
		||||
 | 
			
		||||
  const context: RenderMessage[] = session.context.slice();
 | 
			
		||||
 | 
			
		||||
  const accessStore = useAccessStore();
 | 
			
		||||
@@ -692,10 +692,10 @@ export function Chat() {
 | 
			
		||||
          {!isMobileScreen && (
 | 
			
		||||
            <div className={styles["window-action-button"]}>
 | 
			
		||||
              <IconButton
 | 
			
		||||
                icon={chatStore.config.tightBorder ? <MinIcon /> : <MaxIcon />}
 | 
			
		||||
                icon={config.tightBorder ? <MinIcon /> : <MaxIcon />}
 | 
			
		||||
                bordered
 | 
			
		||||
                onClick={() => {
 | 
			
		||||
                  chatStore.updateConfig(
 | 
			
		||||
                  config.update(
 | 
			
		||||
                    (config) => (config.tightBorder = !config.tightBorder),
 | 
			
		||||
                  );
 | 
			
		||||
                }}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@ import styles from "./home.module.scss";
 | 
			
		||||
import BotIcon from "../icons/bot.svg";
 | 
			
		||||
import LoadingIcon from "../icons/three-dots.svg";
 | 
			
		||||
 | 
			
		||||
import { useChatStore } from "../store";
 | 
			
		||||
import { getCSSVar, useMobileScreen } from "../utils";
 | 
			
		||||
import { Chat } from "./chat";
 | 
			
		||||
 | 
			
		||||
@@ -24,6 +23,7 @@ import {
 | 
			
		||||
  useLocation,
 | 
			
		||||
} from "react-router-dom";
 | 
			
		||||
import { SideBar } from "./sidebar";
 | 
			
		||||
import { useAppConfig } from "../store/config";
 | 
			
		||||
 | 
			
		||||
export function Loading(props: { noLogo?: boolean }) {
 | 
			
		||||
  return (
 | 
			
		||||
@@ -39,7 +39,7 @@ const Settings = dynamic(async () => (await import("./settings")).Settings, {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export function useSwitchTheme() {
 | 
			
		||||
  const config = useChatStore((state) => state.config);
 | 
			
		||||
  const config = useAppConfig();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    document.body.classList.remove("light");
 | 
			
		||||
@@ -80,7 +80,7 @@ const useHasHydrated = () => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function WideScreen() {
 | 
			
		||||
  const config = useChatStore((state) => state.config);
 | 
			
		||||
  const config = useAppConfig();
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@ import {
 | 
			
		||||
  useUpdateStore,
 | 
			
		||||
  useAccessStore,
 | 
			
		||||
  ModalConfigValidator,
 | 
			
		||||
  useAppConfig,
 | 
			
		||||
} from "../store";
 | 
			
		||||
import { Avatar } from "./chat";
 | 
			
		||||
 | 
			
		||||
@@ -180,14 +181,13 @@ function PasswordInput(props: HTMLProps<HTMLInputElement>) {
 | 
			
		||||
export function Settings() {
 | 
			
		||||
  const navigate = useNavigate();
 | 
			
		||||
  const [showEmojiPicker, setShowEmojiPicker] = useState(false);
 | 
			
		||||
  const [config, updateConfig, resetConfig, clearAllData, clearSessions] =
 | 
			
		||||
    useChatStore((state) => [
 | 
			
		||||
      state.config,
 | 
			
		||||
      state.updateConfig,
 | 
			
		||||
      state.resetConfig,
 | 
			
		||||
      state.clearAllData,
 | 
			
		||||
      state.clearSessions,
 | 
			
		||||
    ]);
 | 
			
		||||
  const config = useAppConfig();
 | 
			
		||||
  const updateConfig = config.update;
 | 
			
		||||
  const resetConfig = config.reset;
 | 
			
		||||
  const [clearAllData, clearSessions] = useChatStore((state) => [
 | 
			
		||||
    state.clearAllData,
 | 
			
		||||
    state.clearSessions,
 | 
			
		||||
  ]);
 | 
			
		||||
 | 
			
		||||
  const updateStore = useUpdateStore();
 | 
			
		||||
  const [checkingUpdate, setCheckingUpdate] = useState(false);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { useState, useEffect, useRef } from "react";
 | 
			
		||||
import { useEffect, useRef } from "react";
 | 
			
		||||
 | 
			
		||||
import styles from "./home.module.scss";
 | 
			
		||||
 | 
			
		||||
@@ -10,7 +10,7 @@ import AddIcon from "../icons/add.svg";
 | 
			
		||||
import CloseIcon from "../icons/close.svg";
 | 
			
		||||
import Locale from "../locales";
 | 
			
		||||
 | 
			
		||||
import { useChatStore } from "../store";
 | 
			
		||||
import { useAppConfig, useChatStore } from "../store";
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  MAX_SIDEBAR_WIDTH,
 | 
			
		||||
@@ -20,16 +20,20 @@ import {
 | 
			
		||||
  REPO_URL,
 | 
			
		||||
} from "../constant";
 | 
			
		||||
 | 
			
		||||
import { HashRouter as Router, Link, useNavigate } from "react-router-dom";
 | 
			
		||||
import { Link, useNavigate } from "react-router-dom";
 | 
			
		||||
import { useMobileScreen } from "../utils";
 | 
			
		||||
import { ChatList } from "./chat-list";
 | 
			
		||||
import dynamic from "next/dynamic";
 | 
			
		||||
 | 
			
		||||
const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
 | 
			
		||||
  loading: () => null,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function useDragSideBar() {
 | 
			
		||||
  const limit = (x: number) => Math.min(MAX_SIDEBAR_WIDTH, x);
 | 
			
		||||
 | 
			
		||||
  const chatStore = useChatStore();
 | 
			
		||||
  const config = useAppConfig();
 | 
			
		||||
  const startX = useRef(0);
 | 
			
		||||
  const startDragWidth = useRef(chatStore.config.sidebarWidth ?? 300);
 | 
			
		||||
  const startDragWidth = useRef(config.sidebarWidth ?? 300);
 | 
			
		||||
  const lastUpdateTime = useRef(Date.now());
 | 
			
		||||
 | 
			
		||||
  const handleMouseMove = useRef((e: MouseEvent) => {
 | 
			
		||||
@@ -39,11 +43,11 @@ function useDragSideBar() {
 | 
			
		||||
    lastUpdateTime.current = Date.now();
 | 
			
		||||
    const d = e.clientX - startX.current;
 | 
			
		||||
    const nextWidth = limit(startDragWidth.current + d);
 | 
			
		||||
    chatStore.updateConfig((config) => (config.sidebarWidth = nextWidth));
 | 
			
		||||
    config.update((config) => (config.sidebarWidth = nextWidth));
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const handleMouseUp = useRef(() => {
 | 
			
		||||
    startDragWidth.current = chatStore.config.sidebarWidth ?? 300;
 | 
			
		||||
    startDragWidth.current = config.sidebarWidth ?? 300;
 | 
			
		||||
    window.removeEventListener("mousemove", handleMouseMove.current);
 | 
			
		||||
    window.removeEventListener("mouseup", handleMouseUp.current);
 | 
			
		||||
  });
 | 
			
		||||
@@ -56,15 +60,15 @@ function useDragSideBar() {
 | 
			
		||||
  };
 | 
			
		||||
  const isMobileScreen = useMobileScreen();
 | 
			
		||||
  const shouldNarrow =
 | 
			
		||||
    !isMobileScreen && chatStore.config.sidebarWidth < MIN_SIDEBAR_WIDTH;
 | 
			
		||||
    !isMobileScreen && config.sidebarWidth < MIN_SIDEBAR_WIDTH;
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const barWidth = shouldNarrow
 | 
			
		||||
      ? NARROW_SIDEBAR_WIDTH
 | 
			
		||||
      : limit(chatStore.config.sidebarWidth ?? 300);
 | 
			
		||||
      : limit(config.sidebarWidth ?? 300);
 | 
			
		||||
    const sideBarWidth = isMobileScreen ? "100vw" : `${barWidth}px`;
 | 
			
		||||
    document.documentElement.style.setProperty("--sidebar-width", sideBarWidth);
 | 
			
		||||
  }, [chatStore.config.sidebarWidth, isMobileScreen, shouldNarrow]);
 | 
			
		||||
  }, [config.sidebarWidth, isMobileScreen, shouldNarrow]);
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    onDragMouseDown,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { SubmitKey } from "../store/app";
 | 
			
		||||
import { SubmitKey } from "../store/config";
 | 
			
		||||
 | 
			
		||||
const cn = {
 | 
			
		||||
  WIP: "该功能仍在开发中……",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { SubmitKey } from "../store/app";
 | 
			
		||||
import { SubmitKey } from "../store/config";
 | 
			
		||||
import type { LocaleType } from "./index";
 | 
			
		||||
 | 
			
		||||
const de: LocaleType = {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { SubmitKey } from "../store/app";
 | 
			
		||||
import { SubmitKey } from "../store/config";
 | 
			
		||||
import type { LocaleType } from "./index";
 | 
			
		||||
 | 
			
		||||
const en: LocaleType = {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { SubmitKey } from "../store/app";
 | 
			
		||||
import { SubmitKey } from "../store/config";
 | 
			
		||||
import type { LocaleType } from "./index";
 | 
			
		||||
 | 
			
		||||
const es: LocaleType = {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { SubmitKey } from "../store/app";
 | 
			
		||||
import { SubmitKey } from "../store/config";
 | 
			
		||||
import type { LocaleType } from "./index";
 | 
			
		||||
 | 
			
		||||
const it: LocaleType = {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { SubmitKey } from "../store/app";
 | 
			
		||||
import { SubmitKey } from "../store/config";
 | 
			
		||||
 | 
			
		||||
const jp = {
 | 
			
		||||
  WIP: "この機能は開発中です……",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { SubmitKey } from "../store/app";
 | 
			
		||||
import { SubmitKey } from "../store/config";
 | 
			
		||||
import type { LocaleType } from "./index";
 | 
			
		||||
 | 
			
		||||
const tr: LocaleType = {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { SubmitKey } from "../store/app";
 | 
			
		||||
import { SubmitKey } from "../store/config";
 | 
			
		||||
import type { LocaleType } from "./index";
 | 
			
		||||
 | 
			
		||||
const tw: LocaleType = {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import {
 | 
			
		||||
  ModelConfig,
 | 
			
		||||
  ModelType,
 | 
			
		||||
  useAccessStore,
 | 
			
		||||
  useAppConfig,
 | 
			
		||||
  useChatStore,
 | 
			
		||||
} from "./store";
 | 
			
		||||
import { showToast } from "./components/ui-lib";
 | 
			
		||||
@@ -27,7 +28,7 @@ const makeRequestParam = (
 | 
			
		||||
    sendMessages = sendMessages.filter((m) => m.role !== "assistant");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const modelConfig = { ...useChatStore.getState().config.modelConfig };
 | 
			
		||||
  const modelConfig = { ...useAppConfig.getState().modelConfig };
 | 
			
		||||
 | 
			
		||||
  // @yidadaa: wont send max_tokens, because it is nonsense for Muggles
 | 
			
		||||
  // @ts-expect-error
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										159
									
								
								app/store/app.ts
									
									
									
									
									
								
							
							
						
						
									
										159
									
								
								app/store/app.ts
									
									
									
									
									
								
							@@ -11,6 +11,7 @@ import { isMobileScreen, trimTopic } from "../utils";
 | 
			
		||||
 | 
			
		||||
import Locale from "../locales";
 | 
			
		||||
import { showToast } from "../components/ui-lib";
 | 
			
		||||
import { ModelType, useAppConfig } from "./config";
 | 
			
		||||
 | 
			
		||||
export type Message = ChatCompletionResponseMessage & {
 | 
			
		||||
  date: string;
 | 
			
		||||
@@ -30,133 +31,8 @@ export function createMessage(override: Partial<Message>): Message {
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ChatConfig {
 | 
			
		||||
  historyMessageCount: number; // -1 means all
 | 
			
		||||
  compressMessageLengthThreshold: number;
 | 
			
		||||
  sendBotMessages: boolean; // send bot's message or not
 | 
			
		||||
  submitKey: SubmitKey;
 | 
			
		||||
  avatar: string;
 | 
			
		||||
  fontSize: number;
 | 
			
		||||
  theme: Theme;
 | 
			
		||||
  tightBorder: boolean;
 | 
			
		||||
  sendPreviewBubble: boolean;
 | 
			
		||||
  sidebarWidth: number;
 | 
			
		||||
 | 
			
		||||
  disablePromptHint: boolean;
 | 
			
		||||
 | 
			
		||||
  modelConfig: {
 | 
			
		||||
    model: ModelType;
 | 
			
		||||
    temperature: number;
 | 
			
		||||
    max_tokens: number;
 | 
			
		||||
    presence_penalty: number;
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type ModelConfig = ChatConfig["modelConfig"];
 | 
			
		||||
 | 
			
		||||
export const ROLES: Message["role"][] = ["system", "user", "assistant"];
 | 
			
		||||
 | 
			
		||||
const ENABLE_GPT4 = true;
 | 
			
		||||
 | 
			
		||||
export const ALL_MODELS = [
 | 
			
		||||
  {
 | 
			
		||||
    name: "gpt-4",
 | 
			
		||||
    available: ENABLE_GPT4,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    name: "gpt-4-0314",
 | 
			
		||||
    available: ENABLE_GPT4,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    name: "gpt-4-32k",
 | 
			
		||||
    available: ENABLE_GPT4,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    name: "gpt-4-32k-0314",
 | 
			
		||||
    available: ENABLE_GPT4,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    name: "gpt-3.5-turbo",
 | 
			
		||||
    available: true,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    name: "gpt-3.5-turbo-0301",
 | 
			
		||||
    available: true,
 | 
			
		||||
  },
 | 
			
		||||
] as const;
 | 
			
		||||
 | 
			
		||||
export type ModelType = (typeof ALL_MODELS)[number]["name"];
 | 
			
		||||
 | 
			
		||||
export function limitNumber(
 | 
			
		||||
  x: number,
 | 
			
		||||
  min: number,
 | 
			
		||||
  max: number,
 | 
			
		||||
  defaultValue: number,
 | 
			
		||||
) {
 | 
			
		||||
  if (typeof x !== "number" || isNaN(x)) {
 | 
			
		||||
    return defaultValue;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return Math.min(max, Math.max(min, x));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function limitModel(name: string) {
 | 
			
		||||
  return ALL_MODELS.some((m) => m.name === name && m.available)
 | 
			
		||||
    ? name
 | 
			
		||||
    : ALL_MODELS[4].name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ModalConfigValidator = {
 | 
			
		||||
  model(x: string) {
 | 
			
		||||
    return limitModel(x) as ModelType;
 | 
			
		||||
  },
 | 
			
		||||
  max_tokens(x: number) {
 | 
			
		||||
    return limitNumber(x, 0, 32000, 2000);
 | 
			
		||||
  },
 | 
			
		||||
  presence_penalty(x: number) {
 | 
			
		||||
    return limitNumber(x, -2, 2, 0);
 | 
			
		||||
  },
 | 
			
		||||
  temperature(x: number) {
 | 
			
		||||
    return limitNumber(x, 0, 2, 1);
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const DEFAULT_CONFIG: ChatConfig = {
 | 
			
		||||
  historyMessageCount: 4,
 | 
			
		||||
  compressMessageLengthThreshold: 1000,
 | 
			
		||||
  sendBotMessages: true as boolean,
 | 
			
		||||
  submitKey: SubmitKey.CtrlEnter as SubmitKey,
 | 
			
		||||
  avatar: "1f603",
 | 
			
		||||
  fontSize: 14,
 | 
			
		||||
  theme: Theme.Auto as Theme,
 | 
			
		||||
  tightBorder: false,
 | 
			
		||||
  sendPreviewBubble: true,
 | 
			
		||||
  sidebarWidth: 300,
 | 
			
		||||
 | 
			
		||||
  disablePromptHint: false,
 | 
			
		||||
 | 
			
		||||
  modelConfig: {
 | 
			
		||||
    model: "gpt-3.5-turbo",
 | 
			
		||||
    temperature: 1,
 | 
			
		||||
    max_tokens: 2000,
 | 
			
		||||
    presence_penalty: 0,
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export interface ChatStat {
 | 
			
		||||
  tokenCount: number;
 | 
			
		||||
  wordCount: number;
 | 
			
		||||
@@ -202,7 +78,6 @@ function createEmptySession(): ChatSession {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface ChatStore {
 | 
			
		||||
  config: ChatConfig;
 | 
			
		||||
  sessions: ChatSession[];
 | 
			
		||||
  currentSessionIndex: number;
 | 
			
		||||
  clearSessions: () => void;
 | 
			
		||||
@@ -226,9 +101,6 @@ interface ChatStore {
 | 
			
		||||
  getMessagesWithMemory: () => Message[];
 | 
			
		||||
  getMemoryPrompt: () => Message;
 | 
			
		||||
 | 
			
		||||
  getConfig: () => ChatConfig;
 | 
			
		||||
  resetConfig: () => void;
 | 
			
		||||
  updateConfig: (updater: (config: ChatConfig) => void) => void;
 | 
			
		||||
  clearAllData: () => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -243,9 +115,6 @@ export const useChatStore = create<ChatStore>()(
 | 
			
		||||
    (set, get) => ({
 | 
			
		||||
      sessions: [createEmptySession()],
 | 
			
		||||
      currentSessionIndex: 0,
 | 
			
		||||
      config: {
 | 
			
		||||
        ...DEFAULT_CONFIG,
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      clearSessions() {
 | 
			
		||||
        set(() => ({
 | 
			
		||||
@@ -254,20 +123,6 @@ export const useChatStore = create<ChatStore>()(
 | 
			
		||||
        }));
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      resetConfig() {
 | 
			
		||||
        set(() => ({ config: { ...DEFAULT_CONFIG } }));
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      getConfig() {
 | 
			
		||||
        return get().config;
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      updateConfig(updater) {
 | 
			
		||||
        const config = get().config;
 | 
			
		||||
        updater(config);
 | 
			
		||||
        set(() => ({ config }));
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      selectSession(index: number) {
 | 
			
		||||
        set({
 | 
			
		||||
          currentSessionIndex: index,
 | 
			
		||||
@@ -390,7 +245,7 @@ export const useChatStore = create<ChatStore>()(
 | 
			
		||||
          role: "assistant",
 | 
			
		||||
          streaming: true,
 | 
			
		||||
          id: userMessage.id! + 1,
 | 
			
		||||
          model: get().config.modelConfig.model,
 | 
			
		||||
          model: useAppConfig.getState().modelConfig.model,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // get recent messages
 | 
			
		||||
@@ -443,8 +298,8 @@ export const useChatStore = create<ChatStore>()(
 | 
			
		||||
              controller,
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
          filterBot: !get().config.sendBotMessages,
 | 
			
		||||
          modelConfig: get().config.modelConfig,
 | 
			
		||||
          filterBot: !useAppConfig.getState().sendBotMessages,
 | 
			
		||||
          modelConfig: useAppConfig.getState().modelConfig,
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
@@ -460,7 +315,7 @@ export const useChatStore = create<ChatStore>()(
 | 
			
		||||
 | 
			
		||||
      getMessagesWithMemory() {
 | 
			
		||||
        const session = get().currentSession();
 | 
			
		||||
        const config = get().config;
 | 
			
		||||
        const config = useAppConfig.getState();
 | 
			
		||||
        const messages = session.messages.filter((msg) => !msg.isError);
 | 
			
		||||
        const n = messages.length;
 | 
			
		||||
 | 
			
		||||
@@ -545,14 +400,14 @@ export const useChatStore = create<ChatStore>()(
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const config = get().config;
 | 
			
		||||
        const config = useAppConfig.getState();
 | 
			
		||||
        let toBeSummarizedMsgs = session.messages.slice(
 | 
			
		||||
          session.lastSummarizeIndex,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const historyMsgLength = countMessages(toBeSummarizedMsgs);
 | 
			
		||||
 | 
			
		||||
        if (historyMsgLength > get().config?.modelConfig?.max_tokens ?? 4000) {
 | 
			
		||||
        if (historyMsgLength > config?.modelConfig?.max_tokens ?? 4000) {
 | 
			
		||||
          const n = toBeSummarizedMsgs.length;
 | 
			
		||||
          toBeSummarizedMsgs = toBeSummarizedMsgs.slice(
 | 
			
		||||
            Math.max(0, n - config.historyMessageCount),
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										135
									
								
								app/store/config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								app/store/config.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
			
		||||
import { create } from "zustand";
 | 
			
		||||
import { persist } from "zustand/middleware";
 | 
			
		||||
 | 
			
		||||
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 DEFAULT_CONFIG = {
 | 
			
		||||
  historyMessageCount: 4,
 | 
			
		||||
  compressMessageLengthThreshold: 1000,
 | 
			
		||||
  sendBotMessages: true as boolean,
 | 
			
		||||
  submitKey: SubmitKey.CtrlEnter as SubmitKey,
 | 
			
		||||
  avatar: "1f603",
 | 
			
		||||
  fontSize: 14,
 | 
			
		||||
  theme: Theme.Auto as Theme,
 | 
			
		||||
  tightBorder: false,
 | 
			
		||||
  sendPreviewBubble: true,
 | 
			
		||||
  sidebarWidth: 300,
 | 
			
		||||
 | 
			
		||||
  disablePromptHint: false,
 | 
			
		||||
 | 
			
		||||
  modelConfig: {
 | 
			
		||||
    model: "gpt-3.5-turbo" as ModelType,
 | 
			
		||||
    temperature: 1,
 | 
			
		||||
    max_tokens: 2000,
 | 
			
		||||
    presence_penalty: 0,
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type ChatConfig = typeof DEFAULT_CONFIG;
 | 
			
		||||
 | 
			
		||||
export type ChatConfigStore = ChatConfig & {
 | 
			
		||||
  reset: () => void;
 | 
			
		||||
  update: (updater: (config: ChatConfig) => void) => void;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type ModelConfig = ChatConfig["modelConfig"];
 | 
			
		||||
 | 
			
		||||
const ENABLE_GPT4 = true;
 | 
			
		||||
 | 
			
		||||
export const ALL_MODELS = [
 | 
			
		||||
  {
 | 
			
		||||
    name: "gpt-4",
 | 
			
		||||
    available: ENABLE_GPT4,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    name: "gpt-4-0314",
 | 
			
		||||
    available: ENABLE_GPT4,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    name: "gpt-4-32k",
 | 
			
		||||
    available: ENABLE_GPT4,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    name: "gpt-4-32k-0314",
 | 
			
		||||
    available: ENABLE_GPT4,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    name: "gpt-3.5-turbo",
 | 
			
		||||
    available: true,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    name: "gpt-3.5-turbo-0301",
 | 
			
		||||
    available: true,
 | 
			
		||||
  },
 | 
			
		||||
] as const;
 | 
			
		||||
 | 
			
		||||
export type ModelType = (typeof ALL_MODELS)[number]["name"];
 | 
			
		||||
 | 
			
		||||
export function limitNumber(
 | 
			
		||||
  x: number,
 | 
			
		||||
  min: number,
 | 
			
		||||
  max: number,
 | 
			
		||||
  defaultValue: number,
 | 
			
		||||
) {
 | 
			
		||||
  if (typeof x !== "number" || isNaN(x)) {
 | 
			
		||||
    return defaultValue;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return Math.min(max, Math.max(min, x));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function limitModel(name: string) {
 | 
			
		||||
  return ALL_MODELS.some((m) => m.name === name && m.available)
 | 
			
		||||
    ? name
 | 
			
		||||
    : ALL_MODELS[4].name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ModalConfigValidator = {
 | 
			
		||||
  model(x: string) {
 | 
			
		||||
    return limitModel(x) as ModelType;
 | 
			
		||||
  },
 | 
			
		||||
  max_tokens(x: number) {
 | 
			
		||||
    return limitNumber(x, 0, 32000, 2000);
 | 
			
		||||
  },
 | 
			
		||||
  presence_penalty(x: number) {
 | 
			
		||||
    return limitNumber(x, -2, 2, 0);
 | 
			
		||||
  },
 | 
			
		||||
  temperature(x: number) {
 | 
			
		||||
    return limitNumber(x, 0, 2, 1);
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const CONFIG_KEY = "app-config";
 | 
			
		||||
 | 
			
		||||
export const useAppConfig = create<ChatConfigStore>()(
 | 
			
		||||
  persist(
 | 
			
		||||
    (set, get) => ({
 | 
			
		||||
      ...DEFAULT_CONFIG,
 | 
			
		||||
 | 
			
		||||
      reset() {
 | 
			
		||||
        set(() => ({ ...DEFAULT_CONFIG }));
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      update(updater) {
 | 
			
		||||
        const config = { ...get() };
 | 
			
		||||
        updater(config);
 | 
			
		||||
        set(() => config);
 | 
			
		||||
      },
 | 
			
		||||
    }),
 | 
			
		||||
    {
 | 
			
		||||
      name: CONFIG_KEY,
 | 
			
		||||
    },
 | 
			
		||||
  ),
 | 
			
		||||
);
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
export * from "./app";
 | 
			
		||||
export * from "./update";
 | 
			
		||||
export * from "./access";
 | 
			
		||||
export * from "./config";
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user