|
@@ -42,9 +42,10 @@ 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 { ChangeSessionName, DeleteSession } from "@/api/ai";
|
|
|
+import { ChangeSessionName, DeleteSession, AppParamenters } from "@/api/ai";
|
|
|
import InfiniteScroll from "react-infinite-scroll-component";
|
|
|
import "./assistant.less";
|
|
|
+import { UploadFile } from "@/api";
|
|
|
|
|
|
type AssistantProps = {
|
|
|
agent?: AgentItem;
|
|
@@ -87,6 +88,9 @@ const roles: GetProp<typeof Bubble.List, "roles"> = {
|
|
|
|
|
|
export default (props: AssistantProps) => {
|
|
|
const [senderVal, setSenderVal] = useState("");
|
|
|
+ const [supportFile, setSupportFile] = useState(false);
|
|
|
+ const [fileIds, setFileIds] = useState<Record<string, string>[]>([]);
|
|
|
+ // 聊天相关状态
|
|
|
const {
|
|
|
messages,
|
|
|
setMessages,
|
|
@@ -101,7 +105,7 @@ export default (props: AssistantProps) => {
|
|
|
setConversationList,
|
|
|
loadMoreConversation,
|
|
|
hasMoreConversation,
|
|
|
- refreshConversationList
|
|
|
+ refreshConversationList,
|
|
|
} = useChat({
|
|
|
app_name: props.agent?.key || "",
|
|
|
onSuccess: (msg) => {
|
|
@@ -142,6 +146,24 @@ export default (props: AssistantProps) => {
|
|
|
},
|
|
|
});
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ setAttachmentItems([])
|
|
|
+ setFileIds([]);
|
|
|
+ setOpenAttachment(false);
|
|
|
+ }, [activeConversation]);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ // 清除上传文件
|
|
|
+ setAttachmentItems([])
|
|
|
+ setFileIds([]);
|
|
|
+ setOpenAttachment(false);
|
|
|
+ // 查询是否支持文件
|
|
|
+ props.agent?.key &&
|
|
|
+ AppParamenters({ app_name: props.agent.key }).then((res) => {
|
|
|
+ setSupportFile(!!res?.result?.file_upload.enabled);
|
|
|
+ });
|
|
|
+ }, [props.agent?.key]);
|
|
|
+
|
|
|
const handleChangeConversationName = (conversation: Conversation) => {
|
|
|
let new_name: string;
|
|
|
Modal.info({
|
|
@@ -190,7 +212,7 @@ export default (props: AssistantProps) => {
|
|
|
session_id: conversation.key,
|
|
|
}).then(() => {
|
|
|
message.success("删除成功");
|
|
|
- refreshConversationList()
|
|
|
+ refreshConversationList();
|
|
|
|
|
|
addConversation();
|
|
|
});
|
|
@@ -199,7 +221,7 @@ export default (props: AssistantProps) => {
|
|
|
};
|
|
|
|
|
|
const menuConfig: ConversationsProps["menu"] = (conversation) => {
|
|
|
- if (conversation.key === "1") return undefined;
|
|
|
+ if (conversation.key === "1") return { items: [] }; // 不显示菜单
|
|
|
return {
|
|
|
items: [
|
|
|
{
|
|
@@ -250,6 +272,41 @@ export default (props: AssistantProps) => {
|
|
|
};
|
|
|
}, []);
|
|
|
|
|
|
+ type UploadFileType = {
|
|
|
+ uid?: string;
|
|
|
+ name: string;
|
|
|
+ } & File;
|
|
|
+
|
|
|
+ // 上传文件
|
|
|
+ const uploadRequest: AttachmentsProps["customRequest"] = async (options) => {
|
|
|
+ const { file, onSuccess, onError } = options;
|
|
|
+ if (!supportFile) {
|
|
|
+ message.error("当前应用不支持文件上传");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!file) {
|
|
|
+ message.error("请选择文件");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append("file", file);
|
|
|
+ try {
|
|
|
+ const res = await UploadFile(formData);
|
|
|
+ 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}]);
|
|
|
+ } else {
|
|
|
+ onError?.(res?.message || "上传失败");
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("上传文件失败:", error);
|
|
|
+ onError?.(error as any);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
// 附件组件
|
|
|
const senderHeader = (
|
|
|
<Sender.Header
|
|
@@ -265,7 +322,7 @@ export default (props: AssistantProps) => {
|
|
|
>
|
|
|
<Attachments
|
|
|
ref={attachmentsRef}
|
|
|
- beforeUpload={() => false}
|
|
|
+ // beforeUpload={() => false}
|
|
|
items={attachmentItems}
|
|
|
onChange={({ fileList }) => setAttachmentItems(fileList)}
|
|
|
placeholder={(type) =>
|
|
@@ -280,6 +337,12 @@ 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>
|
|
|
);
|
|
@@ -334,7 +397,12 @@ export default (props: AssistantProps) => {
|
|
|
},
|
|
|
];
|
|
|
});
|
|
|
- onRequest(msg);
|
|
|
+ const ids = supportFile ? fileIds.map(item => Object.values(item)[0]).flat(Infinity) : undefined;
|
|
|
+ onRequest(msg, ids);
|
|
|
+
|
|
|
+ setFileIds([]);
|
|
|
+ setAttachmentItems([]);
|
|
|
+ setOpenAttachment(false);
|
|
|
};
|
|
|
|
|
|
// 点击提示词
|
|
@@ -353,6 +421,10 @@ export default (props: AssistantProps) => {
|
|
|
},
|
|
|
]);
|
|
|
onRequest(msg);
|
|
|
+
|
|
|
+ setAttachmentItems([])
|
|
|
+ setFileIds([]);
|
|
|
+ setOpenAttachment(false);
|
|
|
};
|
|
|
|
|
|
// 停止对话
|
|
@@ -419,7 +491,13 @@ export default (props: AssistantProps) => {
|
|
|
<Spin indicator={<RedoOutlined spin />} size="small" />
|
|
|
</div>
|
|
|
}
|
|
|
- endMessage={<Divider plain><span className="text-12px text-text-secondary">无更多会话~</span></Divider>}
|
|
|
+ endMessage={
|
|
|
+ <Divider plain>
|
|
|
+ <span className="text-12px text-text-secondary">
|
|
|
+ 无更多会话~
|
|
|
+ </span>
|
|
|
+ </Divider>
|
|
|
+ }
|
|
|
scrollableTarget="scrollableDiv"
|
|
|
style={{ overflow: "hidden" }}
|
|
|
>
|
|
@@ -474,7 +552,7 @@ export default (props: AssistantProps) => {
|
|
|
</>
|
|
|
) : (
|
|
|
<Bubble.List
|
|
|
- style={{ maxHeight: contentHeight, padding: '0 20px' }}
|
|
|
+ style={{ maxHeight: contentHeight, padding: "0 20px" }}
|
|
|
autoScroll
|
|
|
roles={roles}
|
|
|
items={messages}
|
|
@@ -513,13 +591,15 @@ export default (props: AssistantProps) => {
|
|
|
header={senderHeader}
|
|
|
loading={loading}
|
|
|
prefix={
|
|
|
- <Button
|
|
|
- type="text"
|
|
|
- icon={<LinkOutlined />}
|
|
|
- onClick={() => {
|
|
|
- setOpenAttachment(!openAttachment);
|
|
|
- }}
|
|
|
- />
|
|
|
+ supportFile && (
|
|
|
+ <Button
|
|
|
+ type="text"
|
|
|
+ icon={<LinkOutlined />}
|
|
|
+ onClick={() => {
|
|
|
+ setOpenAttachment(!openAttachment);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ )
|
|
|
}
|
|
|
value={senderVal}
|
|
|
onPasteFile={(file) => {
|