147 lines
4.6 KiB
JavaScript
147 lines
4.6 KiB
JavaScript
import { Button, Drawer, Input, Space, message } from 'antd';
|
|
import { useChat } from "ai/react";
|
|
import { CodeHighlight } from "@mantine/code-highlight";
|
|
import { DownloadOutlined } from '@ant-design/icons';
|
|
import { useRef, useEffect } from 'react';
|
|
import { useSessionStorage } from 'react-use';
|
|
|
|
export default function ChatAIDrawer({ open, onClose, onExport }) {
|
|
const STORAGE_KEY = 'chat_history';
|
|
const [storedMessages, setStoredMessages] = useSessionStorage(STORAGE_KEY, '[]');
|
|
|
|
const { messages, input, handleSubmit, handleInputChange, isLoading, setMessages } = useChat({
|
|
api: "https://test-ai-quirkyai.vercel.app/api/chat",
|
|
initialMessages: JSON.parse(storedMessages),
|
|
});
|
|
|
|
const messagesEndRef = useRef(null);
|
|
useEffect(() => {
|
|
setStoredMessages(JSON.stringify(messages));
|
|
}, [messages, setStoredMessages]);
|
|
|
|
// 新消息时自动滚动到底部
|
|
useEffect(() => {
|
|
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
}, [messages]);
|
|
|
|
// 修改导出函数,接收单条消息内容
|
|
const handleExport = (content) => {
|
|
try {
|
|
const jsonContent = JSON.parse(content);
|
|
onExport?.(jsonContent);
|
|
} catch (error) {
|
|
console.log(error);
|
|
message.error('导出失败,请重试');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Drawer
|
|
title={
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
<span>AI 助手</span>
|
|
<Button
|
|
size="small"
|
|
onClick={() => {
|
|
setMessages([]);
|
|
setStoredMessages('[]');
|
|
message.success('历史记录已清空');
|
|
}}
|
|
>
|
|
清空历史
|
|
</Button>
|
|
</div>
|
|
}
|
|
placement="right"
|
|
width={600}
|
|
open={open}
|
|
onClose={onClose}
|
|
>
|
|
<div style={{ display: 'flex', flexDirection: 'column', height: 'calc(100vh - 108px)' }}>
|
|
<div style={{
|
|
flex: 1,
|
|
overflowY: 'auto',
|
|
marginBottom: 16,
|
|
padding: '0 16px'
|
|
}}>
|
|
{messages.map((message) => (
|
|
<div
|
|
key={message.id}
|
|
style={{
|
|
marginBottom: 16,
|
|
backgroundColor: message.role === 'assistant' ? '#f0f9ff' : '#f8f9fa',
|
|
padding: 16,
|
|
borderRadius: 12,
|
|
boxShadow: '0 2px 4px rgba(0,0,0,0.05)'
|
|
}}
|
|
>
|
|
<div style={{
|
|
fontWeight: 'bold',
|
|
marginBottom: 8,
|
|
display: 'flex',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
color: message.role === 'assistant' ? '#1677ff' : '#52525b'
|
|
}}>
|
|
<span>{message.role === 'assistant' ? 'AI 助手' : '用户'}</span>
|
|
{message.role === 'assistant' && (
|
|
<Button
|
|
type="link"
|
|
size="small"
|
|
icon={<DownloadOutlined />}
|
|
onClick={() => handleExport(message.content)}
|
|
>
|
|
导出
|
|
</Button>
|
|
)}
|
|
</div>
|
|
<div>
|
|
{message.role === "assistant" ? (
|
|
<CodeHighlight
|
|
code={message.content}
|
|
language="json"
|
|
copyLabel="复制代码"
|
|
copiedLabel="已复制!"
|
|
withLineNumbers
|
|
/>
|
|
) : (
|
|
<div style={{
|
|
whiteSpace: 'pre-wrap',
|
|
wordBreak: 'break-word'
|
|
}}>
|
|
{message.content}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
))}
|
|
<div ref={messagesEndRef} />
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} style={{
|
|
padding: '16px',
|
|
borderTop: '1px solid #f0f0f0',
|
|
backgroundColor: '#fff'
|
|
}}>
|
|
<Space.Compact style={{ width: '100%' }}>
|
|
<Input
|
|
value={input}
|
|
placeholder="请输入您的问题..."
|
|
onChange={handleInputChange}
|
|
disabled={isLoading}
|
|
style={{ borderRadius: '6px 0 0 6px' }}
|
|
/>
|
|
<Button
|
|
type="primary"
|
|
htmlType="submit"
|
|
loading={isLoading}
|
|
style={{ borderRadius: '0 6px 6px 0' }}
|
|
>
|
|
发送
|
|
</Button>
|
|
</Space.Compact>
|
|
</form>
|
|
</div>
|
|
</Drawer>
|
|
);
|
|
} |