Browse Source

fix: 调整AI助手

jiaxing.liao 3 days ago
parent
commit
3c25c90a11

+ 1 - 1
src/hooks/useChat.ts

@@ -178,7 +178,7 @@ export function useChat({ app_name, onSuccess, onUpdate, onError }: ChatProps) {
             content: item.query,
             role: "user",
             status: "done",
-            message_files: item.message_files
+            message_files: item?.message_files?.split(',')?.filter((id: string) => id)
           },
           {
             id: item.id + "_query",

+ 15 - 0
src/main.tsx

@@ -0,0 +1,15 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import { ConfigProvider } from 'antd'
+import zhCN from 'antd/locale/zh_CN'
+import App from './App'
+import './index.css'
+
+ReactDOM.createRoot(document.getElementById('root')!).render(
+  <React.StrictMode>
+    <ConfigProvider locale={zhCN}>
+      <App />
+    </ConfigProvider>
+  </React.StrictMode>,
+)
+

+ 40 - 0
src/pages/ai/AIBubbleFooter.tsx

@@ -0,0 +1,40 @@
+import { Button, message, Space } from "antd";
+import { CopyOutlined, RedoOutlined } from "@ant-design/icons";
+// 底部组件
+const AIBubbleFooter = (props: {
+  content: string;
+  query: string;
+  onRedo: (query: string) => void;
+}) => {
+  const handleCopy = () => {
+    navigator.clipboard.writeText(props.content);
+    message.success("复制成功");
+  };
+
+  const handleRedo = () => {
+    props.onRedo(props.query);
+  };
+
+  return (
+    <Space>
+      <Button
+        type="text"
+        size="small"
+        icon={<CopyOutlined />}
+        onClick={handleCopy}
+      >
+        复制
+      </Button>
+      <Button
+        type="text"
+        size="small"
+        icon={<RedoOutlined />}
+        onClick={handleRedo}
+      >
+        重新生成
+      </Button>
+    </Space>
+  );
+};
+
+export default AIBubbleFooter;

+ 46 - 51
src/pages/ai/Assistant.tsx

@@ -24,7 +24,7 @@ import {
   Modal,
   Input,
 } from "antd";
-import { useEffect, useRef, useState } from "react";
+import { useEffect, useMemo, useRef, useState } from "react";
 import {
   BulbOutlined,
   SmileOutlined,
@@ -34,7 +34,6 @@ import {
   PlusOutlined,
   CloudUploadOutlined,
   LinkOutlined,
-  CopyOutlined,
   RedoOutlined,
   ReadOutlined,
 } from "@ant-design/icons";
@@ -46,6 +45,8 @@ import { ChangeSessionName, DeleteSession, AppParamenters } from "@/api/ai";
 import InfiniteScroll from "react-infinite-scroll-component";
 import "./assistant.less";
 import { UploadFile } from "@/api";
+import UserBubbleFooter from "./UserBubbleFooter";
+import AIBubbleFooter from "./AIBubbleFooter";
 
 type AssistantProps = {
   agent?: AgentItem;
@@ -89,7 +90,9 @@ const roles: GetProp<typeof Bubble.List, "roles"> = {
 export default (props: AssistantProps) => {
   const [senderVal, setSenderVal] = useState("");
   const [supportFile, setSupportFile] = useState(false);
+  const [fileLimit, setFileLimit] = useState(0);
   const [fileIds, setFileIds] = useState<Record<string, string>[]>([]);
+
   // 聊天相关状态
   const {
     messages,
@@ -114,9 +117,10 @@ export default (props: AssistantProps) => {
         const query = arr[messages.length - 2].content as string;
         arr[messages.length - 1].status = "done";
         arr[messages.length - 1].footer = (
-          <BubbleFooter
+          <AIBubbleFooter
             content={arr[messages.length - 1].content as string}
             query={query}
+            onRedo={submitMessage}
           />
         );
         return arr;
@@ -147,20 +151,21 @@ export default (props: AssistantProps) => {
   });
 
   useEffect(() => {
-    setAttachmentItems([])
+    setAttachmentItems([]);
     setFileIds([]);
     setOpenAttachment(false);
   }, [activeConversation]);
 
   useEffect(() => {
     // 清除上传文件
-    setAttachmentItems([])
+    setAttachmentItems([]);
     setFileIds([]);
     setOpenAttachment(false);
     // 查询是否支持文件
     props.agent?.key &&
       AppParamenters({ app_name: props.agent.key }).then((res) => {
         setSupportFile(!!res?.result?.file_upload.enabled);
+        setFileLimit(res?.result?.file_upload?.image.number_limits);
       });
   }, [props.agent?.key]);
 
@@ -293,10 +298,11 @@ export default (props: AssistantProps) => {
     formData.append("file", file);
     try {
       const res = await UploadFile(formData);
-      if(res.code === 1) {
+      if (res.code === 1) {
         onSuccess?.(res.result);
         const uid = (file as UploadFileType).uid || Date.now().toString();
-        res.result?.[0] && setFileIds((ids) => [...ids, {[uid]: res.result[0].id}]);
+        res.result?.[0] &&
+          setFileIds((ids) => [...ids, { [uid]: res.result[0].id }]);
       } else {
         onError?.(res?.message || "上传失败");
       }
@@ -322,9 +328,15 @@ export default (props: AssistantProps) => {
     >
       <Attachments
         ref={attachmentsRef}
-        // beforeUpload={() => false}
         items={attachmentItems}
-        onChange={({ fileList }) => setAttachmentItems(fileList)}
+        maxCount={fileLimit}
+        onChange={({ fileList }) => {
+          const uids = fileList.map((file) => file.uid);
+          setAttachmentItems(fileList);
+          setFileIds((arr) =>
+            arr.filter((item) => uids.includes(Object.keys(item)[0]))
+          );
+        }}
         placeholder={(type) =>
           type === "drop"
             ? {
@@ -338,56 +350,29 @@ export default (props: AssistantProps) => {
         }
         getDropContainer={() => senderRef.current?.nativeElement}
         customRequest={uploadRequest}
-        onRemove={(file) => {
-          setFileIds((arr) => arr.filter((item) => {
-            return !Object.keys(item)?.includes(file.uid)
-          }));
-        }}
       />
     </Sender.Header>
   );
 
-  // 底部组件
-  const BubbleFooter = (props: { content: string; query: string }) => {
-    const handleCopy = () => {
-      navigator.clipboard.writeText(props.content);
-      message.success("复制成功");
-    };
-
-    const handleRedo = () => {
-      submitMessage(props.query);
-    };
-    return (
-      <Space>
-        <Button
-          type="text"
-          size="small"
-          icon={<CopyOutlined />}
-          onClick={handleCopy}
-        >
-          复制
-        </Button>
-        <Button
-          type="text"
-          size="small"
-          icon={<RedoOutlined />}
-          onClick={handleRedo}
-        >
-          重新生成
-        </Button>
-      </Space>
-    );
-  };
-
   // 提交消息
   const submitMessage = (msg: string) => {
     setSenderVal("");
 
+    const ids = supportFile
+      ? fileIds.map((item) => Object.values(item)[0]).flat(Infinity)
+      : undefined;
+
     setMessages((arr) => {
       const index = arr.length;
       return [
         ...arr,
-        { id: index + "", content: msg, status: "done", role: "user" },
+        {
+          id: index + "",
+          content: msg,
+          status: "done",
+          role: "user",
+          message_files: ids,
+        },
         {
           id: index + 1 + "",
           content: "",
@@ -397,7 +382,7 @@ export default (props: AssistantProps) => {
         },
       ];
     });
-    const ids = supportFile ? fileIds.map(item => Object.values(item)[0]).flat(Infinity) : undefined;
+
     onRequest(msg, ids);
 
     setFileIds([]);
@@ -422,7 +407,7 @@ export default (props: AssistantProps) => {
     ]);
     onRequest(msg);
 
-    setAttachmentItems([])
+    setAttachmentItems([]);
     setFileIds([]);
     setOpenAttachment(false);
   };
@@ -439,9 +424,10 @@ export default (props: AssistantProps) => {
           <div className="text-12px text-text-secondary pl-12px">
             (已停止思考)
           </div>
-          <BubbleFooter
+          <AIBubbleFooter
             content={arr[messages.length - 1].content as string}
             query={arr[messages.length - 2].content as string}
+            onRedo={submitMessage}
           />
         </div>
       );
@@ -449,6 +435,15 @@ export default (props: AssistantProps) => {
     });
   };
 
+  const getMessages = useMemo(() => {
+    return messages.map((item) => {
+      return {
+        ...item,
+        footer: <UserBubbleFooter fieldIds={item.message_files} />,
+      };
+    });
+  }, [messages]);
+
   return (
     <>
       <Card
@@ -555,7 +550,7 @@ export default (props: AssistantProps) => {
                     style={{ maxHeight: contentHeight, padding: "0 20px" }}
                     autoScroll
                     roles={roles}
-                    items={messages}
+                    items={getMessages}
                   />
                 )}
               </div>

+ 22 - 0
src/pages/ai/UserBubbleFooter.tsx

@@ -0,0 +1,22 @@
+import { Space, Image, ConfigProvider } from "antd";
+import zhCN from "antd/locale/zh_CN";
+// 用户消息底部组件
+const UserBubbleFooter = (props: { fieldIds?: string[] }) => {
+  return (
+    <ConfigProvider locale={zhCN}>
+      <Space>
+        {props.fieldIds?.map((fieldId) => (
+          <Image
+            className="rounded-8px"
+            width={68}
+            height={68}
+            preview={true}
+            src={`/api/File/Download?fileId=${fieldId}`}
+          />
+        ))}
+      </Space>
+    </ConfigProvider>
+  );
+};
+
+export default UserBubbleFooter;

+ 1 - 1
src/pages/ai/data.tsx

@@ -167,7 +167,7 @@ export const assistantList: AgentItem[] = [
     ]
   },
   {
-    key: "app_generate",
+    key: "demand_generate",
     name: "指令生成",
     icon: icon1,
     description: "我可以帮你快速创建应用~",