Browse Source

feat: close #1301 support message actions

Yidadaa 1 năm trước cách đây
mục cha
commit
222301307f

+ 28 - 0
app/command.ts

@@ -0,0 +1,28 @@
+import { useSearchParams } from "react-router-dom";
+
+type Command = (param: string) => void;
+interface Commands {
+  fill?: Command;
+  submit?: Command;
+  mask?: Command;
+}
+
+export function useCommand(commands: Commands = {}) {
+  const [searchParams, setSearchParams] = useSearchParams();
+
+  if (commands === undefined) return;
+
+  let shouldUpdate = false;
+  searchParams.forEach((param, name) => {
+    const commandName = name as keyof Commands;
+    if (typeof commands[commandName] === "function") {
+      commands[commandName]!(param);
+      searchParams.delete(name);
+      shouldUpdate = true;
+    }
+  });
+
+  if (shouldUpdate) {
+    setSearchParams(searchParams);
+  }
+}

+ 12 - 11
app/components/chat.tsx

@@ -26,12 +26,10 @@ import {
   SubmitKey,
   useChatStore,
   BOT_HELLO,
-  ROLES,
   createMessage,
   useAccessStore,
   Theme,
   useAppConfig,
-  ModelConfig,
   DEFAULT_TOPIC,
 } from "../store";
 
@@ -58,11 +56,8 @@ import { useLocation, useNavigate } from "react-router-dom";
 import { Path } from "../constant";
 import { Avatar } from "./emoji";
 import { MaskAvatar, MaskConfig } from "./mask";
-import {
-  DEFAULT_MASK_AVATAR,
-  DEFAULT_MASK_ID,
-  useMaskStore,
-} from "../store/mask";
+import { useMaskStore } from "../store/mask";
+import { useCommand } from "../command";
 
 const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
   loading: () => <LoadingIcon />,
@@ -478,8 +473,7 @@ export function Chat() {
     }
   };
 
-  // submit user input
-  const onUserSubmit = () => {
+  const doSubmit = (userInput: string) => {
     if (userInput.trim() === "") return;
     setIsLoading(true);
     chatStore.onUserInput(userInput).then(() => setIsLoading(false));
@@ -504,7 +498,7 @@ export function Chat() {
       return;
     }
     if (shouldSubmit(e)) {
-      onUserSubmit();
+      doSubmit(userInput);
       e.preventDefault();
     }
   };
@@ -618,6 +612,13 @@ export function Chat() {
   const isChat = location.pathname === Path.Chat;
   const autoFocus = !isMobileScreen || isChat; // only focus in chat page
 
+  useCommand({
+    fill: setUserInput,
+    submit: (text) => {
+      doSubmit(text);
+    },
+  });
+
   return (
     <div className={styles.chat} key={session.id}>
       <div className="window-header">
@@ -816,7 +817,7 @@ export function Chat() {
             text={Locale.Chat.Send}
             className={styles["chat-input-send"]}
             type="primary"
-            onClick={onUserSubmit}
+            onClick={() => doSubmit(userInput)}
           />
         </div>
       </div>

+ 1 - 0
app/components/home.tsx

@@ -23,6 +23,7 @@ import {
 } from "react-router-dom";
 import { SideBar } from "./sidebar";
 import { useAppConfig } from "../store/config";
+import { useMaskStore } from "../store/mask";
 
 export function Loading(props: { noLogo?: boolean }) {
   return (

+ 2 - 2
app/components/mask.tsx

@@ -20,7 +20,7 @@ import Locale, { AllLangs, Lang } from "../locales";
 import { useNavigate } from "react-router-dom";
 
 import chatStyle from "./chat.module.scss";
-import { useEffect, useState } from "react";
+import { useState } from "react";
 import { downloadAs, readFromFile } from "../utils";
 import { Updater } from "../api/openai/typing";
 import { ModelConfigList } from "./model-config";
@@ -197,7 +197,7 @@ export function ContextPrompts(props: {
             className={chatStyle["context-prompt-button"]}
             onClick={() =>
               addContextPrompt({
-                role: "system",
+                role: "user",
                 content: "",
                 date: "",
               })

+ 13 - 1
app/components/new-chat.tsx

@@ -13,6 +13,7 @@ import { Mask, useMaskStore } from "../store/mask";
 import Locale from "../locales";
 import { useAppConfig, useChatStore } from "../store";
 import { MaskAvatar } from "./mask";
+import { useCommand } from "../command";
 
 function getIntersectionArea(aRect: DOMRect, bRect: DOMRect) {
   const xmin = Math.max(aRect.x, bRect.x);
@@ -108,9 +109,20 @@ export function NewChat() {
 
   const startChat = (mask?: Mask) => {
     chatStore.newSession(mask);
-    navigate(Path.Chat);
+    setTimeout(() => navigate(Path.Chat), 1);
   };
 
+  useCommand({
+    mask: (id) => {
+      try {
+        const mask = maskStore.get(parseInt(id));
+        startChat(mask ?? undefined);
+      } catch {
+        console.error("[New Chat] failed to create chat from mask id=", id);
+      }
+    },
+  });
+
   return (
     <div className={styles["new-chat"]}>
       <div className={styles["mask-header"]}>

+ 2 - 2
app/locales/cn.ts

@@ -4,7 +4,7 @@ const cn = {
   WIP: "该功能仍在开发中……",
   Error: {
     Unauthorized:
-      "现在是未授权状态,请点击左下角[设置](/#/settings)按钮输入访问密码。",
+      "访问密码不正确或为空,请前往[设置](/#/settings)页输入正确的访问密码,或者填入你自己的 OpenAI API Key。",
   },
   ChatItem: {
     ChatItemCount: (count: number) => `${count} 条对话`,
@@ -149,7 +149,7 @@ const cn = {
     },
     AccessCode: {
       Title: "访问密码",
-      SubTitle: "已开启加密访问",
+      SubTitle: "管理员已开启加密访问",
       Placeholder: "请输入访问密码",
     },
     Model: "模型 (model)",

+ 3 - 3
app/store/chat.ts

@@ -7,11 +7,11 @@ import {
   requestChatStream,
   requestWithPrompt,
 } from "../requests";
-import { isMobileScreen, trimTopic } from "../utils";
+import { trimTopic } from "../utils";
 
 import Locale from "../locales";
 import { showToast } from "../components/ui-lib";
-import { DEFAULT_CONFIG, ModelConfig, ModelType, useAppConfig } from "./config";
+import { ModelType } from "./config";
 import { createEmptyMask, Mask } from "./mask";
 import { StoreKey } from "../constant";
 
@@ -33,7 +33,7 @@ export function createMessage(override: Partial<Message>): Message {
   };
 }
 
-export const ROLES: Message["role"][] = ["user", "system", "assistant"];
+export const ROLES: Message["role"][] = ["system", "user", "assistant"];
 
 export interface ChatStat {
   tokenCount: number;

+ 1 - 1
app/store/config.ts

@@ -31,7 +31,7 @@ export const DEFAULT_CONFIG = {
 
   modelConfig: {
     model: "gpt-3.5-turbo" as ModelType,
-    temperature: 1,
+    temperature: 0.5,
     max_tokens: 2000,
     presence_penalty: 0,
     sendMemory: true,

+ 6 - 1
next.config.mjs

@@ -5,7 +5,12 @@ const nextConfig = {
     appDir: true,
   },
   async rewrites() {
-    const ret = [];
+    const ret = [
+      {
+        source: "/api/proxy/:path*",
+        destination: "https://api.openai.com/:path*",
+      },
+    ];
 
     const apiUrl = process.env.API_URL;
     if (apiUrl) {