diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 39abdd97b24..b2dfcd19e9d 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -35,6 +35,9 @@ import BottomIcon from "../icons/bottom.svg"; import StopIcon from "../icons/pause.svg"; import RobotIcon from "../icons/robot.svg"; +import FavoriteIcon from "../icons/star.svg"; +import FavoriteBlackIcon from "../icons/star2.svg"; + import { ChatMessage, SubmitKey, @@ -438,6 +441,10 @@ export function ChatActions(props: { ); const [showModelSelector, setShowModelSelector] = useState(false); + const [favorite, setFavorite] = useState( + chatStore.currentSession().favoriteView, + ); + useEffect(() => { // if current model is not available // switch to first available model @@ -526,6 +533,16 @@ export function ChatActions(props: { icon={} /> + { + chatStore.updateCurrentSession((session) => { + session.favoriteView = !session.favoriteView; + setFavorite(session.favoriteView); + }); + }} + text={favorite ? "退出收藏浏览" : "仅显示收藏"} + icon={favorite ? : } + /> {showModelSelector && ( { deleteMessage(msgId); }; + const onDelete2 = (sid: string) => { + chatStore.updateCurrentSession((session) => { + session.messages = session.messages.map((m) => { + if (m.id === sid) { + if (m.tag === "1") { + const { tag, ...updatedM } = m; + return updatedM; + } else { + return { ...m, tag: "1" }; + } + } + return m; + }); + return session; + }); + }; const onResend = (message: ChatMessage) => { // when it is resending a message @@ -980,6 +1013,7 @@ function _Chat() { const autoFocus = !isMobileScreen; // wont auto focus on mobile screen const showMaxIcon = !isMobileScreen && !clientConfig?.isApp; + const favoriteView = session.favoriteView == true; useCommand({ fill: setUserInput, @@ -1138,126 +1172,146 @@ function _Chat() { const shouldShowClearContextDivider = i === clearContextIndex - 1; - return ( - -
-
-
-
-
- } - onClick={async () => { - const newMessage = await showPrompt( - Locale.Chat.Actions.Edit, - message.content, - 10, - ); - chatStore.updateCurrentSession((session) => { - const m = session.mask.context - .concat(session.messages) - .find((m) => m.id === message.id); - if (m) { - m.content = newMessage; - } - }); - }} - > -
- {isUser ? ( - - ) : ( - <> - {["system"].includes(message.role) ? ( - - ) : ( - - )} - - )} -
- - {showActions && ( -
-
- {message.streaming ? ( - } - onClick={() => onUserStop(message.id ?? i)} - /> - ) : ( - <> - } - onClick={() => onResend(message)} - /> + const shouldShowMessage = !favoriteView || message.tag === "1"; - } - onClick={() => onDelete(message.id ?? i)} + return ( + shouldShowMessage && ( + +
+
+
+
+
+ } + onClick={async () => { + const newMessage = await showPrompt( + Locale.Chat.Actions.Edit, + message.content, + 10, + ); + chatStore.updateCurrentSession((session) => { + const m = session.mask.context + .concat(session.messages) + .find((m) => m.id === message.id); + if (m) { + m.content = newMessage; + } + }); + }} + > +
+ {isUser ? ( + + ) : ( + <> + {["system"].includes(message.role) ? ( + + ) : ( + + )} + + )} +
+ {showActions && ( +
+
+ {message.streaming ? ( } - onClick={() => onPinMessage(message)} + text={Locale.Chat.Actions.Stop} + icon={} + onClick={() => onUserStop(message.id ?? i)} /> - } - onClick={() => copyToClipboard(message.content)} - /> - - )} + ) : ( + <> + } + onClick={() => onResend(message)} + /> + + } + onClick={() => onDelete(message.id ?? i)} + /> + + } + onClick={() => onPinMessage(message)} + /> + } + onClick={() => + copyToClipboard(message.content) + } + /> + + ) : ( + + ) + } + onClick={() => onDelete2(message.id ?? i)} + /> + + )} +
+ )} +
+ {showTyping && ( +
+ {Locale.Chat.Typing}
)} -
- {showTyping && ( -
- {Locale.Chat.Typing} +
+ onRightClick(e, message)} + onDoubleClickCapture={() => { + if (!isMobileScreen) return; + setUserInput(message.content); + }} + fontSize={fontSize} + parentRef={scrollRef} + defaultShow={i >= messages.length - 6} + />
- )} -
- onRightClick(e, message)} - onDoubleClickCapture={() => { - if (!isMobileScreen) return; - setUserInput(message.content); - }} - fontSize={fontSize} - parentRef={scrollRef} - defaultShow={i >= messages.length - 6} - /> -
-
- {isContext - ? Locale.Chat.IsContext - : message.date.toLocaleString()} +
+ {isContext + ? Locale.Chat.IsContext + : message.date.toLocaleString()} +
-
- {shouldShowClearContextDivider && } -
+ {shouldShowClearContextDivider && } + + ) ); })}
diff --git a/app/icons/star.svg b/app/icons/star.svg new file mode 100644 index 00000000000..063906c0b08 --- /dev/null +++ b/app/icons/star.svg @@ -0,0 +1,21 @@ + + + + diff --git a/app/icons/star2.svg b/app/icons/star2.svg new file mode 100644 index 00000000000..fb52b605855 --- /dev/null +++ b/app/icons/star2.svg @@ -0,0 +1,20 @@ + + + + diff --git a/app/store/chat.ts b/app/store/chat.ts index 66a39d2b227..ac3f1df35de 100644 --- a/app/store/chat.ts +++ b/app/store/chat.ts @@ -24,6 +24,7 @@ export type ChatMessage = RequestMessage & { isError?: boolean; id: string; model?: ModelType; + tag?: string; }; export function createMessage(override: Partial): ChatMessage { @@ -54,6 +55,7 @@ export interface ChatSession { clearContextIndex?: number; mask: Mask; + favoriteView?: boolean; } export const DEFAULT_TOPIC = Locale.Store.DefaultTopic;