浏览代码

feat: 新增会话增删查改

liaojiaxing 1 月之前
父节点
当前提交
eb021e862e
共有 8 个文件被更改,包括 604 次插入274 次删除
  1. 63 0
      src/api/ai.ts
  2. 二进制
      src/assets/bg.png
  3. 311 0
      src/hooks/useChat.ts
  4. 33 12
      src/layouts/index.tsx
  5. 0 90
      src/models/aiModel.ts
  6. 3 2
      src/models/userModel.ts
  7. 192 168
      src/pages/ai/Assistant.tsx
  8. 2 2
      src/pages/ai/data.tsx

+ 63 - 0
src/api/ai.ts

@@ -0,0 +1,63 @@
+import { request } from "umi";
+import type { commonParams } from "@/api/index";
+
+/**
+ * 获取会话列表
+ * @param app_name 应用名称
+ * @param page_index 页码
+ */
+export const GetSessionList = (params: {
+  app_name: string;
+  page_index: number;
+}) =>
+  request("/api/ai/chat-session/list", {
+    method: "get",
+    params,
+  });
+
+/**
+ * 获取会话消息列表
+ * @param app_name 应用名称
+ * @param session_id 会话id
+ * @param page_index 页码
+ */
+export const GetSessionMessageList = (params: {
+  app_name: string;
+  session_id: string;
+  page_index: number;
+}) =>
+  request("/api/ai/chat-message/list", {
+    method: "get",
+    params,
+  });
+
+
+/**
+ * 修改会话名称
+ * @param app_name 应用名称
+ * @param session_id 会话id
+ * @param page_index 页码
+ */
+export const ChangeSessionName = (data: {
+  app_name: string;
+  session_id: string;
+  new_name: string;
+}) =>
+  request("/api/ai/chat-session/rename", {
+    method: "post",
+    data,
+  });
+
+  /**
+ * 删除会话
+ * @param app_name 应用名称
+ * @param session_id 会话id
+ */
+export const DeleteSession = (data: {
+  app_name: string;
+  session_id: string;
+}) =>
+  request("/api/ai/chat-session/delete", {
+    method: "post",
+    data,
+  });

二进制
src/assets/bg.png


+ 311 - 0
src/hooks/useChat.ts

@@ -0,0 +1,311 @@
+import { useXAgent, XStream } from "@ant-design/x";
+import { useEffect, useRef, useState } from "react";
+import { useSessionStorageState } from "ahooks";
+import { GetSessionList, GetSessionMessageList } from "@/api/ai";
+
+import type { ConversationsProps } from "@ant-design/x";
+import type { ReactNode } from "react";
+
+// 消息格式
+type MessageItem = {
+  id: string;
+  content: string | ReactNode;
+  role: "user" | "assistant" | "system";
+  status: "loading" | "done" | "error" | "stop";
+  loading?: boolean;
+  footer?: ReactNode;
+};
+
+// 后端返回格式
+type ResponseMessageItem = {
+  answer: string;
+  conversation_id: string;
+  created_at: number;
+  event: "message" | "message_end" | "message_error" | "ping";
+  message_id: string;
+  task_id: string;
+};
+
+type ChatParams = {
+  // 应用名称
+  app_name: string;
+  // 会话内容
+  chat_query: string;
+  // 会话名称 第一次
+  chat_name?: string;
+  // 会话id 后续会话带入
+  conversation_id?: string;
+};
+
+type ChatProps = {
+  // 应用名称
+  app_name: string;
+  // 会话id 后续会话带入
+  conversation_id?: string;
+  // 成功获取会话内容
+  onSuccess?: (data: ResponseMessageItem) => void;
+  // 更新流式消息内容
+  onUpdate: (data: ResponseMessageItem) => void;
+  // 异常
+  onError?: (error: Error) => void;
+};
+
+const defaultConversation = {
+  // 会话id
+  key: "1",
+  label: "新的对话",
+};
+
+export function useChat({ app_name, onSuccess, onUpdate, onError }: ChatProps) {
+  /**
+   * 发送消息加载状态
+   */
+  const [loading, setLoading] = useState(false);
+
+  /**
+   * 加载会话记录列表
+   */
+  const [loadingSession, setLoadingSession] = useState(false);
+
+  /**
+   * 加载消息列表
+   */
+  const [loadingMessages, setLoadingMessages] = useState(false);
+
+  // 用于停止对话
+  const abortController = useRef<AbortController | null>(null);
+
+  /**
+   * 消息列表
+   */
+  const [messages, setMessages] = useState<Array<MessageItem>>([]);
+
+  // 会话列表
+  const [conversationList, setConversationList] = useState<
+    ConversationsProps["items"]
+  >([{ ...defaultConversation }]);
+
+  // 活动对话
+  const [activeConversation, setActiveConversation] = useState("1");
+
+  // 当前智能体对象
+  const [currentAgent, setCurrentAgent] = useSessionStorageState("agent-map");
+
+  useEffect(() => {
+    setLoadingSession(true);
+    GetSessionList({
+      app_name,
+      page_index: 1,
+    })
+      .then((res) => {
+        setConversationList([
+          { ...defaultConversation },
+          ...(res?.result?.model || []).map((item: any) => ({
+            ...item,
+            key: item.sessionId,
+            label: item.name,
+          })),
+        ]);
+      })
+      .finally(() => {
+        setLoadingSession(false);
+      });
+  }, [app_name]);
+
+  /**
+   * 切换会话
+   * @param key 会话id
+   * @returns 
+   */
+  const changeConversation = async (key: string) => {
+    setActiveConversation(key);
+    if (key === "1") {
+      setMessages([]);
+      return;
+    }
+    setLoadingMessages(true);
+    // 获取会话内容
+    try {
+      const res = await GetSessionMessageList({
+        app_name,
+        session_id: key,
+        page_index: 1,
+      });
+
+      const list: MessageItem[] = [];
+      (res?.result?.model || []).forEach((item: any) => {
+        list.push(
+          {
+            id: item.id + "_query",
+            content: item.query,
+            role: "user",
+            status: "done",
+          },
+          {
+            id: item.id + "_query",
+            content: item.answer,
+            role: "assistant",
+            status: "done",
+          }
+        );
+      });
+      setMessages(list);
+    } finally {
+      setLoadingMessages(false);
+    }
+  };
+
+  /**
+   * 封装智能体
+   */
+  const [agent] = useXAgent<ResponseMessageItem>({
+    request: async (message, { onError, onSuccess, onUpdate }) => {
+      abortController.current = new AbortController();
+      const signal = abortController.current.signal;
+      try {
+        setLoading(true);
+        const response = await fetch(
+          "https://design.shalu.com/api/ai/chat-message",
+          {
+            method: "POST",
+            body: JSON.stringify(message),
+            headers: {
+              Authorization: localStorage.getItem("token_a") || "",
+              "Content-Type": "application/json",
+            },
+            signal,
+          }
+        );
+
+        // 判断当前是否流式返回
+        if(response.headers.get('content-type')?.includes('text/event-stream')) {
+          if (response.body) {
+            for await (const chunk of XStream({
+              readableStream: response.body,
+            })) {
+              const data = JSON.parse(chunk.data);
+              if (data?.event === "message") {
+                onUpdate(data);
+              }
+              if (data?.event === "message_end") {
+                onSuccess(data);
+              }
+              if (data?.event === "message_error") {
+                onError(data);
+              }
+              if (data?.event === "ping") {
+                console.log(">>>> stream start <<<<");
+              }
+            }
+          }
+        } else {
+          // 接口异常处理
+          response.json().then(res => {
+            if(res.code === 0 ) {
+              onError?.(Error(res?.error || '请求失败'));
+              cancel();
+            }
+          });
+        }
+      } catch (error) {
+        // 判断是不是 abort 错误
+        if (signal.aborted) {
+          return;
+        }
+        onError(error as Error);
+      } finally {
+        setLoading(false);
+      }
+    },
+  });
+
+  /**
+   * 发起请求
+   * @param chat_query 对话内容
+   */
+  const onRequest = (chat_query: string) => {
+    setConversationList((list) => {
+      return list?.map((item) => {
+        return {
+          ...item,
+          label: item.key === "1" ? chat_query : item.label,
+        };
+      });
+    });
+    agent.request(
+      {
+        app_name,
+        chat_query,
+        chat_name: activeConversation === "1" ? chat_query : undefined,
+        conversation_id:
+          activeConversation === "1" ? undefined : activeConversation,
+      },
+      {
+        onSuccess: (data) => {
+          onSuccess?.(data);
+        },
+        onUpdate: (data) => {
+          onUpdate(data);
+          // 更新会话相关信息
+          if (activeConversation === "1") {
+            setConversationList((list) => {
+              return list?.map((item) => {
+                return {
+                  ...item,
+                  // 更新当前会话id
+                  key: item.key === "1" ? data.conversation_id : item.key,
+                };
+              });
+            });
+            setActiveConversation(data.conversation_id);
+          }
+        },
+        onError: (error) => {
+          console.log("error", error);
+          onError?.(error);
+        },
+      }
+    );
+  };
+
+  /**
+   * 停止对话
+   */
+  const cancel = () => {
+    abortController.current?.abort();
+  };
+
+  /**
+   * 新增会话
+   */
+  const addConversation = () => {
+    setMessages([]);
+    setActiveConversation("1");
+    // 还没产生对话时 直接清除当前对话
+    if (!conversationList?.find((item) => item.key === "1")) {
+      setConversationList([
+        {
+          ...defaultConversation,
+        },
+        ...(conversationList || []),
+      ]);
+    }
+  };
+
+  return {
+    agent,
+    loading,
+    loadingMessages,
+    loadingSession,
+    cancel,
+    messages,
+    setMessages,
+    conversationList,
+    setConversationList,
+    activeConversation,
+    setActiveConversation,
+    onRequest,
+    addConversation,
+    changeConversation,
+  };
+}

+ 33 - 12
src/layouts/index.tsx

@@ -5,29 +5,37 @@ import zhCN from "antd/locale/zh_CN";
 import "dayjs/locale/zh-cn";
 import { DownOutlined, UserOutlined } from "@ant-design/icons";
 import { useModel } from "umi";
+import { useEffect } from "react";
 
 export default function Layout() {
   const location = useLocation();
-  const { userInfo, handleLogout } = useModel("userModel");
+  const { userInfo, handleLogout, checkUserInfo } = useModel("userModel");
 
   const handleLogin = () => {
-    window.open(`/Views/Account/Index.html?ReturnUrl=${window.location.href}`, '_self');
-  }
+    window.open(
+      `/Views/Account/Index.html?ReturnUrl=${window.location.href}`,
+      "_self"
+    );
+  };
+
+  useEffect(() => {
+    checkUserInfo();
+  }, []);
 
   const handleToManagement = () => {
-    window.open(`/Views/Home/Index.html`)
-  }
+    window.open(`/Views/Home/Index.html`);
+  };
 
   const handleToSchool = () => {
-    window.open(`https://college.shalu.com`)
-  }
+    window.open(`https://college.shalu.com`);
+  };
 
   return (
     <ConfigProvider locale={zhCN}>
       <div>
         <div className="header h-56px flex items-center justify-between border-0 border-b border-solid border-gray-200 px-8">
           <img src={logo} alt="logo" className="h-48px w-170px" />
-          
+
           <ul className="menu flex items-center pl-0">
             <Link to="/" className="decoration-none">
               <li
@@ -62,12 +70,20 @@ export default function Layout() {
               <Dropdown
                 menu={{
                   items: [
-                    { key: "1", label: <span>管理后台</span>, onClick: handleToManagement },
-                    { key: "2", label: <span>退出</span>, onClick: handleLogout },
+                    {
+                      key: "1",
+                      label: <span>管理后台</span>,
+                      onClick: handleToManagement,
+                    },
+                    {
+                      key: "2",
+                      label: <span>退出</span>,
+                      onClick: handleLogout,
+                    },
                   ],
                 }}
                 trigger={["click"]}
-                placement="bottomRight" 
+                placement="bottomRight"
                 arrow
               >
                 <span>
@@ -79,7 +95,12 @@ export default function Layout() {
                 </span>
               </Dropdown>
             ) : (
-              <Button className="ml-4px" size="small" onClick={handleLogin} shape="round">
+              <Button
+                className="ml-4px"
+                size="small"
+                onClick={handleLogin}
+                shape="round"
+              >
                 登录
               </Button>
             )}

+ 0 - 90
src/models/aiModel.ts

@@ -1,90 +0,0 @@
-import { useXAgent, XStream } from "@ant-design/x";
-import { useRef, useState } from "react";
-
-type MessageItem = {
-  answer: string;
-  conversation_id: string;
-  created_at: number;
-  event: "message" | "message_end" | "message_error" | "ping";
-  message_id: string;
-  task_id: string;
-};
-
-type ChatParams = {
-  // 应用名称
-  app_name: string;
-  // 会话内容
-  chat_query: string;
-  // 会话名称 第一次
-  chat_name?: string;
-  // 会话id 后续会话带入
-  conversation_id?: string;
-};
-
-export default function aiModel() {
-  const [loading, setLoading] = useState(false);
-  const abortController = useRef<AbortController | null>(null);
-
-  // 封装智能体
-  const [agent] = useXAgent<MessageItem>({
-    request: async (message, { onError, onSuccess, onUpdate }) => {
-      abortController.current = new AbortController();
-      const signal = abortController.current.signal;
-      try {
-        setLoading(true);
-        const response = await fetch(
-          "https://design.shalu.com/api/ai/chat-message",
-          {
-            method: "POST",
-            body: JSON.stringify(message),
-            headers: {
-              Authorization: localStorage.getItem("token_a") || "",
-              "Content-Type": "application/json",
-            },
-            signal
-          }
-        );
-
-        if (response.body) {
-          for await (const chunk of XStream({
-            readableStream: response.body,
-          })) {
-            const data = JSON.parse(chunk.data);
-            if (data?.event === "message") {
-              onUpdate(data);
-            }
-            if (data?.event === "message_end") {
-              onSuccess(data);
-            }
-            if (data?.event === "message_error") {
-              onError(data);
-            }
-            if (data?.event === "ping") {
-              console.log("start");
-            }
-          }
-        }
-      } catch (error) {
-        // 判断是不是 abort 错误
-        if (signal.aborted) {
-          return;
-        }
-        onError(error as Error);
-      } finally {
-        setLoading(false);
-      }
-    },
-  });
-
-  // 停止对话
-  const cancel = () => {
-    abortController.current?.abort();
-  };
-
-  return {
-    agent,
-    loading,
-    setLoading,
-    cancel,
-  };
-}

+ 3 - 2
src/models/userModel.ts

@@ -14,11 +14,11 @@ export type UserInfo = {
 export default function userModel(){
   const [userInfo, setUserInfo] = useState<UserInfo>();
 
-  useEffect(() => {
+  const checkUserInfo = () => {
     GetUserInfo().then((res) => {
       setUserInfo(res?.result);
     });
-  }, []);
+  }
 
   const handleLogout = () => {
     Logout().then((res) => {
@@ -30,5 +30,6 @@ export default function userModel(){
   return {
     userInfo,
     handleLogout,
+    checkUserInfo
   };
 };

+ 192 - 168
src/pages/ai/Assistant.tsx

@@ -9,6 +9,8 @@ import {
   Attachments,
   AttachmentsProps,
 } from "@ant-design/x";
+import { Conversation } from "@ant-design/x/lib/conversations";
+import { useChat } from "@/hooks/useChat";
 
 import {
   Card,
@@ -19,15 +21,10 @@ import {
   Space,
   Spin,
   Typography,
+  Modal,
+  Input,
 } from "antd";
-import {
-  CSSProperties,
-  ReactNode,
-  useEffect,
-  useMemo,
-  useRef,
-  useState,
-} from "react";
+import { useEffect, useRef, useState } from "react";
 import {
   BulbOutlined,
   SmileOutlined,
@@ -39,23 +36,13 @@ import {
   LinkOutlined,
   CopyOutlined,
   RedoOutlined,
+  ReadOutlined,
 } from "@ant-design/icons";
 import type { GetProp, GetRef } from "antd";
 import type { ConversationsProps } from "@ant-design/x";
 import type { AgentItem } from "./data";
 import MarkdownViewer from "@/components/ai/MarkdownViewer";
-import { useModel } from "umi";
-import { useSessionStorageState } from "ahooks";
-
-// 消息类型
-type MessageItem = {
-  id: string;
-  content: string;
-  role: "user" | "assistant" | "system";
-  status: "loading" | "done" | "error" | "stop";
-  loading?: boolean;
-  footer?: ReactNode;
-};
+import { ChangeSessionName, DeleteSession } from "@/api/ai";
 
 type AssistantProps = {
   agent?: AgentItem;
@@ -69,7 +56,7 @@ const roles: GetProp<typeof Bubble.List, "roles"> = {
       icon: <i className="iconfont icon-AI1" />,
       style: { background: "#fde3cf" },
     },
-    typing: { step: 5, interval: 20 },
+    // typing: { step: 5, interval: 20 },
     loadingRender: () => (
       <Space>
         <Spin size="small" />
@@ -77,12 +64,12 @@ const roles: GetProp<typeof Bubble.List, "roles"> = {
       </Space>
     ),
     messageRender: (content) => {
-      return content ? (
+      return typeof content === "string" ? (
         <Typography>
           <MarkdownViewer content={content} />
         </Typography>
       ) : (
-        <></>
+        content
       );
     },
     header: "易码工坊AI助手",
@@ -93,40 +80,146 @@ const roles: GetProp<typeof Bubble.List, "roles"> = {
   },
 };
 
-const defaultConversation = {
-  // 会话id
-  key: "1",
-  label: "新的对话",
-};
-
 export default (props: AssistantProps) => {
-  const { agent, loading, cancel } = useModel("aiModel");
   const [senderVal, setSenderVal] = useState("");
-  const [messages, setMessages] = useState<Array<MessageItem>>([]);
-  const [conversationList, setConversationList] = useState<
-    ConversationsProps["items"]
-  >([{ ...defaultConversation }]);
-  const [activeConversation, setActiveConversation] = useState("1");
+  const {
+    messages,
+    setMessages,
+    activeConversation,
+    changeConversation,
+    conversationList,
+    onRequest,
+    cancel,
+    loading,
+    loadingSession,
+    addConversation,
+    setConversationList,
+  } = useChat({
+    app_name: props.agent?.key || "",
+    onSuccess: (msg) => {
+      setMessages((messages) => {
+        const arr = [...messages];
+        const query = arr[messages.length - 2].content as string;
+        arr[messages.length - 1].status = "done";
+        arr[messages.length - 1].footer = (
+          <BubbleFooter
+            content={arr[messages.length - 1].content as string}
+            query={query}
+          />
+        );
+        return arr;
+      });
+    },
+    onUpdate: (msg) => {
+      setMessages((messages) => {
+        const arr = [...messages];
+        arr[messages.length - 1].content += msg.answer;
+        arr[messages.length - 1].id = msg.message_id;
+        arr[messages.length - 1].loading = false;
+        arr[messages.length - 1].status = "error";
+        return arr;
+      });
+    },
+    onError: (error) => {
+      message.error(error.message);
+      setMessages((messages) => {
+        const arr = [...messages];
+        arr[messages.length - 1].content = (
+          <Typography.Text type="danger">{error.message}</Typography.Text>
+        );
+        arr[messages.length - 1].status = "error";
+        arr[messages.length - 1].loading = false;
+        return arr;
+      });
+    },
+  });
 
-  const [currentAgent, setCurrentAgent] = useSessionStorageState("agent-map");
-  const menuConfig: ConversationsProps["menu"] = (conversation) => ({
-    items: [
-      {
-        label: "修改对话名称",
-        key: "edit",
-        icon: <EditOutlined />,
+  const handleChangeConversationName = (conversation: Conversation) => {
+    let new_name: string;
+    Modal.info({
+      title: "修改对话名称",
+      okText: "提交",
+      closable: true,
+      content: (
+        <div>
+          <Input
+            type="text"
+            defaultValue={conversation.label + ""}
+            onChange={(e) => {
+              new_name = e.target.value;
+            }}
+          />
+        </div>
+      ),
+      onOk: () => {
+        return ChangeSessionName({
+          app_name: props.agent?.key || "",
+          session_id: conversation.key,
+          new_name,
+        }).then(() => {
+          message.success("修改成功");
+          setConversationList((list) =>
+            list?.map((item) =>
+              item.key === conversation.key
+                ? { ...item, label: new_name }
+                : item
+            )
+          );
+        });
       },
-      {
-        label: "删除对话",
-        key: "del",
-        icon: <DeleteOutlined />,
-        danger: true,
+    });
+  };
+
+  const handleDeleteConversation = (conversation: Conversation) => {
+    Modal.confirm({
+      title: "删除对话",
+      content: "是否删除对话?",
+      okText: "删除",
+      cancelText: "取消",
+      onOk: () => {
+        return DeleteSession({
+          app_name: props.agent?.key || "",
+          session_id: conversation.key,
+        }).then(() => {
+          message.success("删除成功");
+          setConversationList((list) =>
+            list?.filter((item) => item.key !== conversation.key)
+          );
+
+          addConversation();
+        });
       },
-    ],
-    onClick: (menuInfo) => {
-      message.info(`Click ${conversation.key} - ${menuInfo.key}`);
-    },
-  });
+    });
+  };
+
+  const menuConfig: ConversationsProps["menu"] = (conversation) => {
+    if (conversation.key === "1") return undefined;
+    return {
+      items: [
+        {
+          label: "修改对话名称",
+          key: "edit",
+          icon: <EditOutlined />,
+        },
+        {
+          label: "删除对话",
+          key: "del",
+          icon: <DeleteOutlined />,
+          danger: true,
+        },
+      ],
+      onClick: (menuInfo) => {
+        // 修改对话名称
+        if (menuInfo.key === "edit") {
+          handleChangeConversationName(conversation);
+        }
+        // 删除对话
+        if (menuInfo.key === "del") {
+          handleDeleteConversation(conversation);
+        }
+      },
+    };
+  };
 
   const [openAttachment, setOpenAttachment] = useState(false);
   const attachmentsRef = useRef<GetRef<typeof Attachments>>(null);
@@ -135,22 +228,18 @@ export default (props: AssistantProps) => {
     GetProp<AttachmentsProps, "items">
   >([]);
   const contentRef = useRef<HTMLDivElement>(null);
+  const [contentHeight, setContentHeight] = useState(0);
 
-  const contentStyle = useMemo((): CSSProperties => {
-    if (!contentRef.current) return {};
-    return {
-      maxHeight: contentRef.current?.clientHeight,
-      overflowY: "auto",
-    };
-  }, [contentRef.current]);
-
+  const setHeight = () => {
+    setContentHeight(contentRef.current?.clientHeight || 0);
+  };
   useEffect(() => {
-    // 切换类型时清除回话 加载回话列表
-    if (agent) {
-      setMessages([]);
-      setActiveConversation("1");
-    }
-  }, [props.agent]);
+    setHeight();
+    window.addEventListener("resize", setHeight);
+    return () => {
+      window.removeEventListener("resize", setHeight);
+    };
+  }, []);
 
   // 附件组件
   const senderHeader = (
@@ -218,68 +307,6 @@ export default (props: AssistantProps) => {
     );
   };
 
-  // 发起请求
-  const onRequest = (message: string) => {
-    agent.request(
-      {
-        app_name: "app1",
-        chat_name: activeConversation === "1" ? "新会话" : undefined,
-        chat_query: message,
-        conversation_id:
-          activeConversation === "1" ? undefined : activeConversation,
-      },
-      {
-        onSuccess: (msg) => {
-          console.log("success", msg);
-          setMessages((messages) => {
-            const arr = [...messages];
-            const query = arr[messages.length - 2].content;
-            arr[messages.length - 1].status = "done";
-            arr[messages.length - 1].footer = (
-              <BubbleFooter
-                content={arr[messages.length - 1].content}
-                query={query}
-              />
-            );
-            return arr;
-          });
-        },
-        onError: (error) => {
-          console.log("err:", error);
-          
-        },
-        onUpdate: (msg) => {
-          console.log("update", msg);
-          setMessages((messages) => {
-            const arr = [...messages];
-            arr[messages.length - 1].content += msg.answer;
-            arr[messages.length - 1].id = msg.message_id;
-            arr[messages.length - 1].loading = false;
-            // 第一次提交后保存会话记录
-            if (
-              !conversationList?.find(
-                (item) => item.key === msg.conversation_id
-              )
-            ) {
-              setConversationList((list) => {
-                return list?.map((item) => {
-                  return {
-                    ...item,
-                    key: msg.conversation_id,
-                    label: message,
-                  };
-                });
-              });
-              setActiveConversation(msg.conversation_id);
-            }
-
-            return arr;
-          });
-        },
-      }
-    );
-  };
-
   // 提交消息
   const submitMessage = (msg: string) => {
     setSenderVal("");
@@ -303,7 +330,6 @@ export default (props: AssistantProps) => {
 
   // 点击提示词
   const handlePromptItem = (item: any) => {
-    console.log(item);
     const msg = item.data.description || item.data.label;
     const index = messages.length;
     setMessages([
@@ -329,29 +355,17 @@ export default (props: AssistantProps) => {
       arr[messages.length - 1].loading = false;
       arr[messages.length - 1].footer = (
         <div>
-          <div className="text-12px text-text-secondary">已停止思考</div>
-          <BubbleFooter content={arr[messages.length - 1].content} query={arr[messages.length - 2].content}/>
+          <div className="text-12px text-text-secondary pl-12px">(已停止思考)</div>
+          <BubbleFooter
+            content={arr[messages.length - 1].content as string}
+            query={arr[messages.length - 2].content as string}
+          />
         </div>
       );
       return arr;
     });
   };
 
-  // 新增会话
-  const handleAddConversation = () => {
-    setMessages([]);
-    // 还没产生对话时 直接清除当前对话
-    if (!conversationList?.find((item) => item.key === "1")) {
-      setConversationList([
-        {
-          ...defaultConversation,
-        },
-        ...(conversationList || []),
-      ]);
-      setActiveConversation("1");
-    }
-  };
-
   return (
     <>
       <Card
@@ -373,29 +387,34 @@ export default (props: AssistantProps) => {
       >
         <XProvider direction="ltr">
           <Flex style={{ height: "100%" }} gap={12}>
-            <div className="w-200px">
-              <div className="w-full px-12px">
-                <Button
-                  type="primary"
-                  className="w-full"
-                  icon={<PlusOutlined />}
-                  onClick={handleAddConversation}
-                >
-                  新对话
-                </Button>
+            <Spin spinning={loadingSession}>
+              <div className="w-200px">
+                <div className="w-full px-12px">
+                  <Button
+                    type="primary"
+                    className="w-full"
+                    icon={<PlusOutlined />}
+                    onClick={addConversation}
+                  >
+                    新对话
+                  </Button>
+                </div>
+                <Conversations
+                  style={{ width: 200 }}
+                  activeKey={activeConversation}
+                  onActiveChange={changeConversation}
+                  menu={menuConfig}
+                  items={conversationList}
+                />
               </div>
-              <Conversations
-                style={{ width: 200 }}
-                defaultActiveKey="1"
-                activeKey={activeConversation}
-                onActiveChange={setActiveConversation}
-                menu={menuConfig}
-                items={conversationList}
-              />
-            </div>
+            </Spin>
             <Divider type="vertical" style={{ height: "100%" }} />
             <Flex vertical style={{ flex: 1 }} gap={8}>
-              <div className="flex-1" ref={contentRef} style={contentStyle}>
+              <div
+                className="flex-1"
+                ref={contentRef}
+                style={{ height: contentHeight }}
+              >
                 {!messages.length ? (
                   <>
                     <div className="mt-20 mb-10">
@@ -421,7 +440,12 @@ export default (props: AssistantProps) => {
                     />
                   </>
                 ) : (
-                  <Bubble.List autoScroll roles={roles} items={messages} />
+                  <Bubble.List
+                    style={{ maxHeight: contentHeight }}
+                    autoScroll
+                    roles={roles}
+                    items={messages}
+                  />
                 )}
               </div>
               <Prompts
@@ -438,7 +462,7 @@ export default (props: AssistantProps) => {
                   },
                   {
                     key: "3",
-                    icon: <SmileOutlined style={{ color: "#52C41A" }} />,
+                    icon: <ReadOutlined style={{ color: "#52C41A" }} />,
                     label: "问题解答",
                   },
                 ]}

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

@@ -114,14 +114,14 @@ export const assistantList: AgentItem[] = [
   },
   {
     key: "app6",
-    name: "文档管理",
+    name: "文档生成",
     icon: icon6,
     description: "文档管理方面的一些问题",
     promptsItems: [
       {
         key: "1",
         icon: <SmileOutlined style={{ color: "#52C41A" }} />,
-        description: "如何上传文档?",
+        description: "生成一份系统操作手册文档?",
       },
       {
         key: "2",