mirror of
				https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
				synced 2025-11-04 08:13:43 +08:00 
			
		
		
		
	refactor: #121 trigger auto-cmp with / prefix
This commit is contained in:
		@@ -102,7 +102,7 @@ export function ChatList() {
 | 
			
		||||
      state.currentSessionIndex,
 | 
			
		||||
      state.selectSession,
 | 
			
		||||
      state.removeSession,
 | 
			
		||||
    ]
 | 
			
		||||
    ],
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
@@ -128,7 +128,7 @@ function useSubmitHandler() {
 | 
			
		||||
 | 
			
		||||
  const shouldSubmit = (e: KeyboardEvent) => {
 | 
			
		||||
    if (e.key !== "Enter") return false;
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      (config.submitKey === SubmitKey.AltEnter && e.altKey) ||
 | 
			
		||||
      (config.submitKey === SubmitKey.CtrlEnter && e.ctrlKey) ||
 | 
			
		||||
@@ -170,7 +170,10 @@ export function PromptHints(props: {
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean }) {
 | 
			
		||||
export function Chat(props: {
 | 
			
		||||
  showSideBar?: () => void;
 | 
			
		||||
  sideBarShowing?: boolean;
 | 
			
		||||
}) {
 | 
			
		||||
  type RenderMessage = Message & { preview?: boolean };
 | 
			
		||||
 | 
			
		||||
  const chatStore = useChatStore();
 | 
			
		||||
@@ -190,11 +193,10 @@ export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean
 | 
			
		||||
  const [promptHints, setPromptHints] = useState<Prompt[]>([]);
 | 
			
		||||
  const onSearch = useDebouncedCallback(
 | 
			
		||||
    (text: string) => {
 | 
			
		||||
      if (chatStore.config.disablePromptHint) return;
 | 
			
		||||
      setPromptHints(promptStore.search(text));
 | 
			
		||||
    },
 | 
			
		||||
    100,
 | 
			
		||||
    { leading: true, trailing: true }
 | 
			
		||||
    { leading: true, trailing: true },
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const onPromptSelect = (prompt: Prompt) => {
 | 
			
		||||
@@ -203,20 +205,31 @@ export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean
 | 
			
		||||
    inputRef.current?.focus();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const scrollInput = () => {
 | 
			
		||||
    const dom = inputRef.current;
 | 
			
		||||
    if (!dom) return;
 | 
			
		||||
    const paddingBottomNum: number = parseInt(
 | 
			
		||||
      window.getComputedStyle(dom).paddingBottom,
 | 
			
		||||
      10,
 | 
			
		||||
    );
 | 
			
		||||
    dom.scrollTop = dom.scrollHeight - dom.offsetHeight + paddingBottomNum;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // only search prompts when user input is short
 | 
			
		||||
  const SEARCH_TEXT_LIMIT = 30;
 | 
			
		||||
  const onInput = (text: string) => {
 | 
			
		||||
    const textareaDom = inputRef.current
 | 
			
		||||
    if (textareaDom) {
 | 
			
		||||
      const paddingBottomNum: number = parseInt(window.getComputedStyle(textareaDom).paddingBottom, 10);
 | 
			
		||||
      textareaDom.scrollTop = textareaDom.scrollHeight - textareaDom.offsetHeight + paddingBottomNum;
 | 
			
		||||
    }
 | 
			
		||||
    scrollInput();
 | 
			
		||||
    setUserInput(text);
 | 
			
		||||
    const n = text.trim().length;
 | 
			
		||||
    if (n === 0 || n > SEARCH_TEXT_LIMIT) {
 | 
			
		||||
 | 
			
		||||
    // clear search results
 | 
			
		||||
    if (n === 0) {
 | 
			
		||||
      setPromptHints([]);
 | 
			
		||||
    } else {
 | 
			
		||||
      onSearch(text);
 | 
			
		||||
    } else if (!chatStore.config.disablePromptHint && n < SEARCH_TEXT_LIMIT) {
 | 
			
		||||
      // check if need to trigger auto completion
 | 
			
		||||
      if (text.startsWith("/") && text.length > 1) {
 | 
			
		||||
        onSearch(text.slice(1));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
@@ -285,7 +298,7 @@ export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean
 | 
			
		||||
              preview: true,
 | 
			
		||||
            },
 | 
			
		||||
          ]
 | 
			
		||||
        : []
 | 
			
		||||
        : [],
 | 
			
		||||
    )
 | 
			
		||||
    .concat(
 | 
			
		||||
      userInput.length > 0
 | 
			
		||||
@@ -297,7 +310,7 @@ export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean
 | 
			
		||||
              preview: true,
 | 
			
		||||
            },
 | 
			
		||||
          ]
 | 
			
		||||
        : []
 | 
			
		||||
        : [],
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
  // auto scroll
 | 
			
		||||
@@ -380,32 +393,33 @@ export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean
 | 
			
		||||
                  </div>
 | 
			
		||||
                )}
 | 
			
		||||
                <div className={styles["chat-message-item"]}>
 | 
			
		||||
                  {(!isUser && !(message.preview || message.content.length === 0)) && (
 | 
			
		||||
                    <div className={styles["chat-message-top-actions"]}>
 | 
			
		||||
                      {message.streaming ? (
 | 
			
		||||
                        <div
 | 
			
		||||
                          className={styles["chat-message-top-action"]}
 | 
			
		||||
                          onClick={() => onUserStop(i)}
 | 
			
		||||
                        >
 | 
			
		||||
                          {Locale.Chat.Actions.Stop}
 | 
			
		||||
                        </div>
 | 
			
		||||
                      ) : (
 | 
			
		||||
                        <div
 | 
			
		||||
                          className={styles["chat-message-top-action"]}
 | 
			
		||||
                          onClick={() => onResend(i)}
 | 
			
		||||
                        >
 | 
			
		||||
                          {Locale.Chat.Actions.Retry}
 | 
			
		||||
                        </div>
 | 
			
		||||
                      )}
 | 
			
		||||
                  {!isUser &&
 | 
			
		||||
                    !(message.preview || message.content.length === 0) && (
 | 
			
		||||
                      <div className={styles["chat-message-top-actions"]}>
 | 
			
		||||
                        {message.streaming ? (
 | 
			
		||||
                          <div
 | 
			
		||||
                            className={styles["chat-message-top-action"]}
 | 
			
		||||
                            onClick={() => onUserStop(i)}
 | 
			
		||||
                          >
 | 
			
		||||
                            {Locale.Chat.Actions.Stop}
 | 
			
		||||
                          </div>
 | 
			
		||||
                        ) : (
 | 
			
		||||
                          <div
 | 
			
		||||
                            className={styles["chat-message-top-action"]}
 | 
			
		||||
                            onClick={() => onResend(i)}
 | 
			
		||||
                          >
 | 
			
		||||
                            {Locale.Chat.Actions.Retry}
 | 
			
		||||
                          </div>
 | 
			
		||||
                        )}
 | 
			
		||||
 | 
			
		||||
                      <div
 | 
			
		||||
                        className={styles["chat-message-top-action"]}
 | 
			
		||||
                        onClick={() => copyToClipboard(message.content)}
 | 
			
		||||
                      >
 | 
			
		||||
                        {Locale.Chat.Actions.Copy}
 | 
			
		||||
                        <div
 | 
			
		||||
                          className={styles["chat-message-top-action"]}
 | 
			
		||||
                          onClick={() => copyToClipboard(message.content)}
 | 
			
		||||
                        >
 | 
			
		||||
                          {Locale.Chat.Actions.Copy}
 | 
			
		||||
                        </div>
 | 
			
		||||
                      </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                  )}
 | 
			
		||||
                    )}
 | 
			
		||||
                  {(message.preview || message.content.length === 0) &&
 | 
			
		||||
                  !isUser ? (
 | 
			
		||||
                    <LoadingIcon />
 | 
			
		||||
@@ -560,7 +574,7 @@ export function Home() {
 | 
			
		||||
      state.newSession,
 | 
			
		||||
      state.currentSessionIndex,
 | 
			
		||||
      state.removeSession,
 | 
			
		||||
    ]
 | 
			
		||||
    ],
 | 
			
		||||
  );
 | 
			
		||||
  const loading = !useHasHydrated();
 | 
			
		||||
  const [showSideBar, setShowSideBar] = useState(true);
 | 
			
		||||
@@ -653,7 +667,11 @@ export function Home() {
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        ) : (
 | 
			
		||||
          <Chat key="chat" showSideBar={() => setShowSideBar(true)} sideBarShowing={showSideBar} />
 | 
			
		||||
          <Chat
 | 
			
		||||
            key="chat"
 | 
			
		||||
            showSideBar={() => setShowSideBar(true)}
 | 
			
		||||
            sideBarShowing={showSideBar}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -77,7 +77,7 @@ const cn = {
 | 
			
		||||
    Prompt: {
 | 
			
		||||
      Disable: {
 | 
			
		||||
        Title: "禁用提示词自动补全",
 | 
			
		||||
        SubTitle: "禁用后将无法自动根据输入补全",
 | 
			
		||||
        SubTitle: "在输入框开头输入 / 即可触发自动补全",
 | 
			
		||||
      },
 | 
			
		||||
      List: "自定义提示词列表",
 | 
			
		||||
      ListCount: (builtin: number, custom: number) =>
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,7 @@ const en: LocaleType = {
 | 
			
		||||
    Prompt: {
 | 
			
		||||
      Disable: {
 | 
			
		||||
        Title: "Disable auto-completion",
 | 
			
		||||
        SubTitle: "After disabling, auto-completion will not be available",
 | 
			
		||||
        SubTitle: "Input / to trigger auto-completion",
 | 
			
		||||
      },
 | 
			
		||||
      List: "Prompt List",
 | 
			
		||||
      ListCount: (builtin: number, custom: number) =>
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ const tw: LocaleType = {
 | 
			
		||||
      Retry: "重試",
 | 
			
		||||
    },
 | 
			
		||||
    Typing: "正在輸入…",
 | 
			
		||||
    Input: (submitKey: string) =>  {
 | 
			
		||||
    Input: (submitKey: string) => {
 | 
			
		||||
      var inputHints = `輸入訊息後,按下 ${submitKey} 鍵即可發送`;
 | 
			
		||||
      if (submitKey === String(SubmitKey.Enter)) {
 | 
			
		||||
        inputHints += ",Shift + Enter 鍵換行";
 | 
			
		||||
@@ -78,7 +78,7 @@ const tw: LocaleType = {
 | 
			
		||||
    Prompt: {
 | 
			
		||||
      Disable: {
 | 
			
		||||
        Title: "停用提示詞自動補全",
 | 
			
		||||
        SubTitle: "若停用後,將無法自動根據輸入進行補全",
 | 
			
		||||
        SubTitle: "在輸入框開頭輸入 / 即可觸發自動補全",
 | 
			
		||||
      },
 | 
			
		||||
      List: "自定義提示詞列表",
 | 
			
		||||
      ListCount: (builtin: number, custom: number) =>
 | 
			
		||||
@@ -124,8 +124,7 @@ const tw: LocaleType = {
 | 
			
		||||
    Prompt: {
 | 
			
		||||
      History: (content: string) =>
 | 
			
		||||
        "這是 AI 與用戶的歷史聊天總結,作為前情提要:" + content,
 | 
			
		||||
      Topic:
 | 
			
		||||
        "直接返回這句話的簡要主題,無須解釋,若無主題,請直接返回「閒聊」",
 | 
			
		||||
      Topic: "直接返回這句話的簡要主題,無須解釋,若無主題,請直接返回「閒聊」",
 | 
			
		||||
      Summarize:
 | 
			
		||||
        "簡要總結一下你和用戶的對話,作為後續的上下文提示 prompt,且字數控制在 50 字以內",
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user