mirror of
https://github.com/usememos/memos.git
synced 2025-06-05 22:09:59 +02:00
* feat(#1568): Added "ask ai" section session splitting function Added "ask ai" section session splitting function Optimize the "ask ai" dialogue style * fix(#1568): Fix wrong attribute "appearance" * fix(#1568): Add ts type define * fix(#1568): Add ts type define * fix(#1568): Resolve the issue of components not being stretched when only user input is available * feat(#1568): New session automatic switching function * refactor(#1729): remove unused code * feat(#1568): New Remove Session Function New Remove Session Function Rename some methods
This commit is contained in:
@ -1,5 +1,18 @@
|
||||
import { Button, Textarea } from "@mui/joy";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
Input,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Modal,
|
||||
ModalClose,
|
||||
ModalDialog,
|
||||
Stack,
|
||||
Textarea,
|
||||
Typography,
|
||||
} from "@mui/joy";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import * as api from "@/helpers/api";
|
||||
@ -9,6 +22,8 @@ import { useMessageStore } from "@/store/zustand/message";
|
||||
import Icon from "./Icon";
|
||||
import { generateDialog } from "./Dialog";
|
||||
import showSettingDialog from "./SettingDialog";
|
||||
import { defaultMessageGroup, MessageGroup, useMessageGroupStore } from "@/store/zustand/message-group";
|
||||
import { PlusIcon, Trash2Icon } from "lucide-react";
|
||||
|
||||
type Props = DialogProps;
|
||||
|
||||
@ -16,7 +31,8 @@ const AskAIDialog: React.FC<Props> = (props: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { destroy, hide } = props;
|
||||
const fetchingState = useLoading(false);
|
||||
const messageStore = useMessageStore();
|
||||
const [messageGroup, setMessageGroup] = useState<MessageGroup>(defaultMessageGroup);
|
||||
const messageStore = useMessageStore(messageGroup)();
|
||||
const [isEnabled, setIsEnabled] = useState<boolean>(true);
|
||||
const [isInIME, setIsInIME] = useState(false);
|
||||
const [question, setQuestion] = useState<string>("");
|
||||
@ -41,7 +57,7 @@ const AskAIDialog: React.FC<Props> = (props: Props) => {
|
||||
const handleKeyDown = (event: React.KeyboardEvent) => {
|
||||
if (event.key === "Enter" && !event.shiftKey && !isInIME) {
|
||||
event.preventDefault();
|
||||
handleSendQuestionButtonClick();
|
||||
handleSendQuestionButtonClick().then();
|
||||
}
|
||||
};
|
||||
|
||||
@ -76,18 +92,108 @@ const AskAIDialog: React.FC<Props> = (props: Props) => {
|
||||
});
|
||||
};
|
||||
|
||||
const [anchorEl, setAnchorEl] = useState<null | (EventTarget & Element)>(null);
|
||||
const handleMenuOpen = (event: React.SyntheticEvent) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
const handleMenuClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
const handleOptionSelect = (option: MessageGroup) => {
|
||||
setMessageGroup(option);
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const [isAddMessageGroupDlgOpen, setIsAddMessageGroupDlgOpen] = useState<boolean>(false);
|
||||
const [groupName, setGroupName] = useState<string>("");
|
||||
|
||||
const messageGroupStore = useMessageGroupStore();
|
||||
const messageGroupList = messageGroupStore.groupList;
|
||||
|
||||
const handleOpenDialog = () => {
|
||||
setIsAddMessageGroupDlgOpen(true);
|
||||
};
|
||||
|
||||
const handleRemoveDialog = () => {
|
||||
setMessageGroup(messageGroupStore.removeGroup(messageGroup));
|
||||
};
|
||||
|
||||
const handleCloseDialog = () => {
|
||||
setIsAddMessageGroupDlgOpen(false);
|
||||
setGroupName("");
|
||||
};
|
||||
|
||||
const handleAddMessageGroupDlgConfirm = () => {
|
||||
const newMessageGroup: MessageGroup = {
|
||||
name: groupName,
|
||||
messageStorageId: "message-storage-" + groupName,
|
||||
};
|
||||
messageGroupStore.addGroup(newMessageGroup);
|
||||
setMessageGroup(newMessageGroup);
|
||||
handleCloseDialog();
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
handleCloseDialog();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="dialog-header-container">
|
||||
<p className="title-text flex flex-row items-center">
|
||||
<Icon.Bot className="mr-1 w-5 h-auto opacity-80" />
|
||||
{t("ask-ai.title")}
|
||||
<span className="button-group" style={{ marginLeft: "10px" }}>
|
||||
<Button color={"primary"} onClick={handleMenuOpen}>
|
||||
<div className="button-len-max-150">{messageGroup.name}</div>
|
||||
</Button>
|
||||
<Button color={"success"} onClick={handleOpenDialog}>
|
||||
<PlusIcon size={"13px"} />
|
||||
</Button>
|
||||
<Button color={"danger"} onClick={handleRemoveDialog}>
|
||||
<Trash2Icon size={"13px"} />
|
||||
</Button>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleMenuClose}>
|
||||
<MenuItem onClick={() => handleOptionSelect(defaultMessageGroup)}>{defaultMessageGroup.name}</MenuItem>
|
||||
{messageGroupList.map((messageGroup, index) => (
|
||||
<MenuItem key={index} onClick={() => handleOptionSelect(messageGroup)}>
|
||||
{messageGroup.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
<Modal open={isAddMessageGroupDlgOpen} onClose={handleCloseDialog}>
|
||||
<ModalDialog aria-labelledby="basic-modal-dialog-title" sx={{ maxWidth: 500 }}>
|
||||
<ModalClose />
|
||||
<Typography id="basic-modal-dialog-title" component="h2">
|
||||
{t("ask-ai.create-message-group-title")}
|
||||
</Typography>
|
||||
<Stack spacing={2}>
|
||||
<FormControl>
|
||||
<FormLabel>{t("ask-ai.label-message-group-name-title")}</FormLabel>
|
||||
<Input
|
||||
value={groupName}
|
||||
onChange={(e) => setGroupName(e.target.value)}
|
||||
placeholder={t("ask-ai.label-message-group-name-title")}
|
||||
/>
|
||||
</FormControl>
|
||||
<Typography>
|
||||
<Button onClick={handleCancel} style={{ marginRight: "10px" }}>
|
||||
{t("common.cancel")}
|
||||
</Button>
|
||||
<Button onClick={handleAddMessageGroupDlgConfirm}>{t("common.confirm")}</Button>
|
||||
</Typography>
|
||||
</Stack>
|
||||
</ModalDialog>
|
||||
</Modal>
|
||||
<button className="btn close-btn" onClick={() => hide()}>
|
||||
<Icon.X />
|
||||
</button>
|
||||
</div>
|
||||
<div className="dialog-content-container !w-112 max-w-full">
|
||||
<Stack spacing={2} style={{ width: "100%" }}>
|
||||
{messageList.map((message, index) => (
|
||||
<div key={index} className="w-full flex flex-col justify-start items-start space-y-2">
|
||||
{message.role === "user" ? (
|
||||
@ -106,6 +212,7 @@ const AskAIDialog: React.FC<Props> = (props: Props) => {
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</Stack>
|
||||
{fetchingState.isLoading && (
|
||||
<p className="w-full py-2 mt-4 flex flex-row justify-center items-center">
|
||||
<Icon.Loader className="w-5 h-auto animate-spin" />
|
||||
|
@ -9,3 +9,30 @@ body {
|
||||
#root {
|
||||
@apply w-full h-full;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 0; /* 按钮之间的间距 */
|
||||
}
|
||||
|
||||
.button-group>button:not(:first-child):not(:last-child) {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.button-group>button:first-child {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.button-group>button:last-child {
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
|
||||
|
||||
.button-len-max-150 {
|
||||
max-width: 150px; /* 按钮的最大宽度 */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
@ -380,7 +380,10 @@
|
||||
"title": "Ask AI",
|
||||
"not-enabled": "You have not set up your OpenAI API key.",
|
||||
"go-to-settings": "Go to settings",
|
||||
"placeholder": "Ask anything…"
|
||||
"placeholder": "Ask anything…",
|
||||
"default-message-group-title": "Default Session",
|
||||
"create-message-group-title": "Create Session",
|
||||
"label-message-group-name-title": "Session Name"
|
||||
},
|
||||
"embed-memo": {
|
||||
"title": "Embed Memo",
|
||||
|
@ -23,7 +23,11 @@
|
||||
"go-to-settings": "前往设置",
|
||||
"not-enabled": "您尚未设置 OpenAI API 密钥。",
|
||||
"placeholder": "随便问",
|
||||
"title": "问 AI"
|
||||
"title": "问 AI",
|
||||
"default-message-group-title": "默认会话",
|
||||
"create-message-group-title": "新建会话",
|
||||
"label-message-group-name-title": "会话名称"
|
||||
|
||||
},
|
||||
"auth": {
|
||||
"host-tip": "你正在注册为管理员用户账号。",
|
||||
|
41
web/src/store/zustand/message-group.ts
Normal file
41
web/src/store/zustand/message-group.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
import { t } from "i18next";
|
||||
|
||||
export interface MessageGroup {
|
||||
name: string;
|
||||
messageStorageId: string;
|
||||
}
|
||||
|
||||
interface MessageGroupState {
|
||||
groupList: MessageGroup[];
|
||||
getState: () => MessageGroupState;
|
||||
addGroup: (group: MessageGroup) => void;
|
||||
removeGroup: (group: MessageGroup) => MessageGroup;
|
||||
}
|
||||
|
||||
export const defaultMessageGroup: MessageGroup = {
|
||||
name: t("ask-ai.default-message-group-title"),
|
||||
messageStorageId: "message-storage",
|
||||
};
|
||||
|
||||
export const useMessageGroupStore = create<MessageGroupState>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
groupList: [],
|
||||
getState: () => get(),
|
||||
addGroup: (group: MessageGroup) => set((state) => ({ groupList: [...state.groupList, group] })),
|
||||
removeGroup: (group: MessageGroup) => {
|
||||
set((state) => ({
|
||||
groupList: state.groupList.filter((i) => i.name != group.name || i.messageStorageId != group.messageStorageId),
|
||||
}));
|
||||
localStorage.removeItem(group.messageStorageId);
|
||||
const groupList = get().groupList;
|
||||
return groupList.length > 0 ? groupList[groupList.length - 1] : defaultMessageGroup;
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: "message-group-storage",
|
||||
}
|
||||
)
|
||||
);
|
@ -1,5 +1,6 @@
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
import { MessageGroup } from "@/store/zustand/message-group";
|
||||
|
||||
export interface Message {
|
||||
role: "user" | "assistant";
|
||||
@ -12,7 +13,8 @@ interface MessageState {
|
||||
addMessage: (message: Message) => void;
|
||||
}
|
||||
|
||||
export const useMessageStore = create<MessageState>()(
|
||||
export const useMessageStore = (options: MessageGroup) => {
|
||||
return create<MessageState>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
messageList: [],
|
||||
@ -20,7 +22,8 @@ export const useMessageStore = create<MessageState>()(
|
||||
addMessage: (message: Message) => set((state) => ({ messageList: [...state.messageList, message] })),
|
||||
}),
|
||||
{
|
||||
name: "message-storage",
|
||||
name: options.messageStorageId,
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
|
Reference in New Issue
Block a user