From 222301307fd13ec2ed9828cc0dc4f8b2e309c0d6 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 9 May 2023 00:39:00 +0800 Subject: [PATCH] feat: close #1301 support message actions --- app/command.ts | 28 ++++++++++++++++++++++++++++ app/components/chat.tsx | 23 ++++++++++++----------- app/components/home.tsx | 1 + app/components/mask.tsx | 4 ++-- app/components/new-chat.tsx | 14 +++++++++++++- app/locales/cn.ts | 4 ++-- app/store/chat.ts | 6 +++--- app/store/config.ts | 2 +- next.config.mjs | 7 ++++++- 9 files changed, 68 insertions(+), 21 deletions(-) create mode 100644 app/command.ts diff --git a/app/command.ts b/app/command.ts new file mode 100644 index 00000000..40bad92b --- /dev/null +++ b/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); + } +} diff --git a/app/components/chat.tsx b/app/components/chat.tsx index ca51a06a..8786877b 100644 --- a/app/components/chat.tsx +++ b/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: () => , @@ -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 (
@@ -816,7 +817,7 @@ export function Chat() { text={Locale.Chat.Send} className={styles["chat-input-send"]} type="primary" - onClick={onUserSubmit} + onClick={() => doSubmit(userInput)} />
diff --git a/app/components/home.tsx b/app/components/home.tsx index a83a7798..4c3d0a64 100644 --- a/app/components/home.tsx +++ b/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 ( diff --git a/app/components/mask.tsx b/app/components/mask.tsx index 964a3cc3..9794c974 100644 --- a/app/components/mask.tsx +++ b/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: "", }) diff --git a/app/components/new-chat.tsx b/app/components/new-chat.tsx index 42612e0a..81858fb0 100644 --- a/app/components/new-chat.tsx +++ b/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 (
diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 8bec7c40..112b3b5c 100644 --- a/app/locales/cn.ts +++ b/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)", diff --git a/app/store/chat.ts b/app/store/chat.ts index 0d66580d..c938d787 100644 --- a/app/store/chat.ts +++ b/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 { }; } -export const ROLES: Message["role"][] = ["user", "system", "assistant"]; +export const ROLES: Message["role"][] = ["system", "user", "assistant"]; export interface ChatStat { tokenCount: number; diff --git a/app/store/config.ts b/app/store/config.ts index da77c7b3..926c296f 100644 --- a/app/store/config.ts +++ b/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, diff --git a/next.config.mjs b/next.config.mjs index 3f7c2fb6..c62f8840 100644 --- a/next.config.mjs +++ b/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) {