From a3a9e5a5253b132a8bef484978e01073e679bb2a Mon Sep 17 00:00:00 2001 From: Zhang Minghan Date: Fri, 26 Jan 2024 10:39:50 +0800 Subject: [PATCH] feat: update quota tooltip and article generation style mobile adapter, edit message and delete message alpha version (#51) --- adapter/adapter.go | 22 +-- addition/generation/prompt.go | 8 +- app/src/api/conversation.ts | 43 ++++ app/src/assets/pages/article.less | 6 + app/src/assets/pages/chat.less | 1 - app/src/components/EditorProvider.tsx | 4 +- app/src/components/Message.tsx | 187 ++++++++++-------- app/src/components/Tips.tsx | 20 +- app/src/components/home/ChatInterface.tsx | 5 +- .../components/home/assemblies/ChatInput.tsx | 17 +- app/src/events/connection.ts | 2 + app/src/resources/i18n/cn.json | 2 + app/src/resources/i18n/en.json | 4 +- app/src/resources/i18n/ja.json | 4 +- app/src/resources/i18n/ru.json | 4 +- app/src/routes/Article.tsx | 16 +- app/src/routes/Sharing.tsx | 2 +- app/src/store/settings.ts | 8 +- manager/chat.go | 1 - manager/chat_completions.go | 1 - manager/completions.go | 1 - manager/connection.go | 2 + manager/conversation/conversation.go | 14 ++ manager/images.go | 5 +- manager/manager.go | 34 ++++ 25 files changed, 271 insertions(+), 142 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index a7ad755..479c5db 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -31,8 +31,6 @@ type ChatProps struct { RequestProps Model string - Plan bool - Infinity bool Message []globals.Message Token int PresencePenalty *float32 @@ -56,7 +54,7 @@ func createChatRequest(conf globals.ChannelConfig, props *ChatProps, hook global Message: props.Message, Token: utils.Multi( props.Token == 0, - utils.Multi(props.Infinity || props.Plan, nil, utils.ToPtr(2500)), + utils.ToPtr(2500), &props.Token, ), PresencePenalty: props.PresencePenalty, @@ -74,7 +72,7 @@ func createChatRequest(conf globals.ChannelConfig, props *ChatProps, hook global Message: props.Message, Token: utils.Multi( props.Token == 0, - utils.Multi(props.Infinity || props.Plan, nil, utils.ToPtr(2500)), + utils.ToPtr(2500), &props.Token, ), PresencePenalty: props.PresencePenalty, @@ -136,7 +134,7 @@ func createChatRequest(conf globals.ChannelConfig, props *ChatProps, hook global return dashscope.NewChatInstanceFromConfig(conf).CreateStreamChatRequest(&dashscope.ChatProps{ Model: model, Message: props.Message, - Token: utils.Multi(props.Infinity || props.Plan, 2048, props.Token), + Token: props.Token, Temperature: props.Temperature, TopP: props.TopP, TopK: props.TopK, @@ -164,7 +162,7 @@ func createChatRequest(conf globals.ChannelConfig, props *ChatProps, hook global return skylark.NewChatInstanceFromConfig(conf).CreateStreamChatRequest(&skylark.ChatProps{ Model: model, Message: props.Message, - Token: utils.Multi(props.Token == 0, 4096, props.Token), + Token: props.Token, TopP: props.TopP, TopK: props.TopK, Temperature: props.Temperature, @@ -178,7 +176,7 @@ func createChatRequest(conf globals.ChannelConfig, props *ChatProps, hook global return zhinao.NewChatInstanceFromConfig(conf).CreateStreamChatRequest(&zhinao.ChatProps{ Model: model, Message: props.Message, - Token: utils.Multi(props.Infinity || props.Plan, nil, utils.ToPtr(2048)), + Token: &props.Token, TopP: props.TopP, TopK: props.TopK, Temperature: props.Temperature, @@ -193,13 +191,9 @@ func createChatRequest(conf globals.ChannelConfig, props *ChatProps, hook global case globals.OneAPIChannelType: return oneapi.NewChatInstanceFromConfig(conf).CreateStreamChatRequest(&oneapi.ChatProps{ - Model: model, - Message: props.Message, - Token: utils.Multi( - props.Token == 0, - utils.Multi(props.Plan || props.Infinity, nil, utils.ToPtr(2500)), - &props.Token, - ), + Model: model, + Message: props.Message, + Token: &props.Token, PresencePenalty: props.PresencePenalty, FrequencyPenalty: props.FrequencyPenalty, Temperature: props.Temperature, diff --git a/addition/generation/prompt.go b/addition/generation/prompt.go index 6c71c4c..e8aaba3 100644 --- a/addition/generation/prompt.go +++ b/addition/generation/prompt.go @@ -18,11 +18,9 @@ func CreateGeneration(group, model, prompt, path string, plan bool, hook func(bu buffer := utils.NewBuffer(model, message, channel.ChargeInstance.GetCharge(model)) err := channel.NewChatRequest(group, &adapter.ChatProps{ - Model: model, - Message: message, - Plan: plan, - Infinity: true, - Buffer: *buffer, + Model: model, + Message: message, + Buffer: *buffer, }, func(data string) error { buffer.Write(data) hook(buffer, data) diff --git a/app/src/api/conversation.ts b/app/src/api/conversation.ts index e3be613..b0965fb 100644 --- a/app/src/api/conversation.ts +++ b/app/src/api/conversation.ts @@ -61,6 +61,27 @@ export class Conversation { this.sendRestartEvent(); break; + case "edit": + const index = ev.index ?? -1; + const message = ev.message ?? ""; + + if (this.isValidIndex(index)) { + this.data[index].content = message; + this.sendEditEvent(index, message); + this.triggerCallback(); + } + break; + + case "remove": + const idx = ev.index ?? -1; + + if (this.isValidIndex(idx)) { + delete this.data[idx]; + this.sendRemoveEvent(idx); + this.triggerCallback(); + } + break; + default: console.debug( `[conversation] unknown event: ${ev.event} (from: ${ev.id})`, @@ -82,6 +103,10 @@ export class Conversation { this.sendEvent("stop"); } + public isValidIndex(idx: number): boolean { + return idx >= 0 && idx < this.data.length; + } + public sendRestartEvent() { this.sendEvent("restart"); } @@ -90,6 +115,24 @@ export class Conversation { this.sendEvent("mask", JSON.stringify(mask.context)); } + public sendEditEvent(id: number, message: string) { + this.sendEvent( + "edit", + JSON.stringify({ + message: `${id}:${message}`, + }), + ); + } + + public sendRemoveEvent(id: number) { + this.sendEvent( + "remove", + JSON.stringify({ + message: `${id}`, + }), + ); + } + public sendShareEvent(refer: string) { this.sendEvent("share", refer); } diff --git a/app/src/assets/pages/article.less b/app/src/assets/pages/article.less index 774f13f..33058da 100644 --- a/app/src/assets/pages/article.less +++ b/app/src/assets/pages/article.less @@ -30,6 +30,12 @@ align-items: center; } + .article-action { + @media (max-width: 768px) { + flex-direction: column; + } + } + .article-content { display: flex; flex-direction: column; diff --git a/app/src/assets/pages/chat.less b/app/src/assets/pages/chat.less index f74169b..81ba726 100644 --- a/app/src/assets/pages/chat.less +++ b/app/src/assets/pages/chat.less @@ -63,7 +63,6 @@ .content-wrapper { display: flex; - flex-direction: row; max-width: 100%; .message-toolbar { diff --git a/app/src/components/EditorProvider.tsx b/app/src/components/EditorProvider.tsx index f694606..4510c5b 100644 --- a/app/src/components/EditorProvider.tsx +++ b/app/src/components/EditorProvider.tsx @@ -6,7 +6,7 @@ import { DialogTitle, DialogTrigger, } from "./ui/dialog.tsx"; -import { Maximize, Image, MenuSquare, PanelRight, XSquare } from "lucide-react"; +import { Maximize, Image, MenuSquare, PanelRight, Eraser } from "lucide-react"; import { useTranslation } from "react-i18next"; import "@/assets/common/editor.less"; import { Textarea } from "./ui/textarea.tsx"; @@ -64,7 +64,7 @@ function RichEditor({ value, onChange, maxLength }: RichEditorProps) { className={`h-8 w-8 p-0`} onClick={() => value && onChange("")} > - +
void; + onEvent?: (event: string, index?: number, message?: string) => void; ref?: Ref; }; function MessageSegment(props: MessageProps) { - const { t } = useTranslation(); const ref = useRef(null); const { message } = props; return (
- {message.quota && message.quota !== 0 ? ( - - - -
- - - {(message.quota < 0 ? 0 : message.quota).toFixed(2)} - -
-
- - -

{t("quota-description")}

-
-
-
- ) : null} +
); } -function MessageContent({ message, end, onEvent }: MessageProps) { - const { t } = useTranslation(); +type MessageQuotaProps = { + message: Message; +}; + +function MessageQuota({ message }: MessageQuotaProps) { + const trigger = useMemo( + () => + message.quota && ( +
+ + + {(message.quota < 0 ? 0 : message.quota).toFixed(2)} + +
+ ), + [message], + ); return ( -
+ message.quota && + message.quota !== 0 && ( + + +

{message.quota.toFixed(6)}

+
+ ) + ); +} + +function MessageContent({ message, end, index, onEvent }: MessageProps) { + const { t } = useTranslation(); + const isAssistant = message.role === "assistant"; + + return ( +
{message.content.length ? ( @@ -84,62 +96,67 @@ function MessageContent({ message, end, onEvent }: MessageProps) { )}
- {message.role === "assistant" && ( -
- - - - - - {end && ( - - onEvent && - onEvent(message.end !== false ? "restart" : "stop") - } - > - {message.end !== false ? ( - <> - - {t("message.restart")} - - ) : ( - <> - - {t("message.stop")} - - )} - - )} - copyClipboard(filterMessage(message.content))} - > - - {t("message.copy")} - +
+ + + + + + {isAssistant && end && ( - useInputValue("input", filterMessage(message.content)) + onEvent && onEvent(message.end !== false ? "restart" : "stop") } > - - {t("message.use")} + {message.end !== false ? ( + <> + + {t("message.restart")} + + ) : ( + <> + + {t("message.stop")} + + )} - - saveAsFile( - `message-${message.role}.txt`, - filterMessage(message.content), - ) - } - > - - {t("message.save")} - - - -
- )} + )} + copyClipboard(filterMessage(message.content))} + > + + {t("message.copy")} + + + useInputValue("input", filterMessage(message.content)) + } + > + + {t("message.use")} + + + + {t("message.edit")} + + + + {t("message.remove")} + + + saveAsFile( + `message-${message.role}.txt`, + filterMessage(message.content), + ) + } + > + + {t("message.save")} + +
+
+
); } diff --git a/app/src/components/Tips.tsx b/app/src/components/Tips.tsx index 061c4f4..fda099a 100644 --- a/app/src/components/Tips.tsx +++ b/app/src/components/Tips.tsx @@ -15,12 +15,21 @@ import { type TipsProps = { content?: string; + trigger?: React.ReactNode; children?: React.ReactNode; className?: string; + classNamePopup?: string; hideTimeout?: number; }; -function Tips({ content, children, className, hideTimeout }: TipsProps) { +function Tips({ + content, + trigger, + children, + className, + classNamePopup, + hideTimeout, +}: TipsProps) { const timeout = hideTimeout ?? 2500; const comp = useMemo( () => ( @@ -49,14 +58,17 @@ function Tips({ content, children, className, hideTimeout }: TipsProps) { - + {trigger ?? } - {comp} + {comp} {comp} diff --git a/app/src/components/home/ChatInterface.tsx b/app/src/components/home/ChatInterface.tsx index b3c419c..5af7f79 100644 --- a/app/src/components/home/ChatInterface.tsx +++ b/app/src/components/home/ChatInterface.tsx @@ -64,13 +64,16 @@ function ChatInterface({ setTarget, setWorking }: ChatInterfaceProps) { { + onEvent={(e: string, index?: number, message?: string) => { connectionEvent.emit({ id: current, event: e, + index, + message, }); }} key={i} + index={i} /> ))}
diff --git a/app/src/components/home/assemblies/ChatInput.tsx b/app/src/components/home/assemblies/ChatInput.tsx index 0abe558..8c058c6 100644 --- a/app/src/components/home/assemblies/ChatInput.tsx +++ b/app/src/components/home/assemblies/ChatInput.tsx @@ -21,9 +21,10 @@ function ChatInput({ onEnterPressed, }: ChatInputProps) { const { t } = useTranslation(); - const [pressed, setPressed] = React.useState(false); const sender = useSelector(senderSelector); + // sender: Ctrl + Enter if false, Enter if true + return (