dify ai
This commit is contained in:
218
src/components/difyChatAi/index.jsx
Normal file
218
src/components/difyChatAi/index.jsx
Normal file
@@ -0,0 +1,218 @@
|
||||
import { Button, Drawer, Input, Space, message } from 'antd';
|
||||
import { CodeHighlight } from "@mantine/code-highlight";
|
||||
import { DownloadOutlined, EditOutlined, CheckOutlined, CloseOutlined } from '@ant-design/icons';
|
||||
import { useRef, useEffect, useState } from 'react';
|
||||
import { useDifyChat } from '@/hooks/aichat';
|
||||
|
||||
export default function DifyChatDrawer({ open, onClose, onExport }) {
|
||||
const {
|
||||
messages,
|
||||
setMessages,
|
||||
isLoading,
|
||||
sendMessage,
|
||||
clearHistory,
|
||||
storedMessages,
|
||||
setStoredMessages
|
||||
} = useDifyChat();
|
||||
|
||||
const [input, setInput] = useState('');
|
||||
const messagesEndRef = useRef(null);
|
||||
|
||||
const [editingMessageId, setEditingMessageId] = useState(null);
|
||||
const [editingContent, setEditingContent] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
}, [messages]);
|
||||
|
||||
const handleSendMessage = async (e) => {
|
||||
e.preventDefault();
|
||||
await sendMessage(input);
|
||||
setInput('');
|
||||
};
|
||||
|
||||
const handleEdit = (message) => {
|
||||
if(isLoading) return;
|
||||
setEditingContent(message.content);
|
||||
setEditingMessageId(message.id);
|
||||
};
|
||||
|
||||
const handleSaveEdit = () => {
|
||||
try {
|
||||
JSON.parse(editingContent);
|
||||
setMessages(messages.map(msg =>
|
||||
msg.id === editingMessageId
|
||||
? { ...msg, content: editingContent }
|
||||
: msg
|
||||
));
|
||||
setEditingMessageId(null);
|
||||
message.success('编辑成功');
|
||||
} catch (error) {
|
||||
message.error('请输入有效的 JSON 格式');
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancelEdit = () => {
|
||||
setEditingMessageId(null);
|
||||
setEditingContent('');
|
||||
};
|
||||
|
||||
const handleExport = (content) => {
|
||||
try {
|
||||
const jsonContent = JSON.parse(content);
|
||||
onExport?.(jsonContent);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
message.error('导出失败,请重试');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
title={
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-lg font-medium text-gray-800">AI 助手</span>
|
||||
<Button
|
||||
size="small"
|
||||
className="hover:bg-gray-100"
|
||||
onClick={clearHistory}
|
||||
>
|
||||
清空历史
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
placement="right"
|
||||
width={800}
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
className="rounded-l-xl"
|
||||
>
|
||||
<div className="flex flex-col h-[calc(100vh-108px)]">
|
||||
<div className="flex-1 overflow-y-auto px-4 space-y-6">
|
||||
{messages.map((message) => (
|
||||
<div
|
||||
key={message.id}
|
||||
className={`rounded-lg p-4 transition-all ${
|
||||
message.role === 'assistant'
|
||||
? 'bg-blue-50 hover:bg-blue-100'
|
||||
: 'bg-gray-50 hover:bg-gray-100'
|
||||
}`}
|
||||
>
|
||||
<div className="flex justify-between items-center mb-3">
|
||||
<span className={`font-medium ${
|
||||
message.role === 'assistant' ? 'text-blue-600' : 'text-gray-600'
|
||||
}`}>
|
||||
{message.role === 'assistant' ? 'AI 助手' : '用户'}
|
||||
</span>
|
||||
{message.role === 'assistant' && (
|
||||
<Space>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<EditOutlined />}
|
||||
disabled={isLoading}
|
||||
onClick={() => handleEdit(message)}
|
||||
className="text-gray-500 hover:text-blue-600"
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<DownloadOutlined />}
|
||||
onClick={() => handleExport(message.content)}
|
||||
className="text-gray-500 hover:text-blue-600"
|
||||
>
|
||||
导出
|
||||
</Button>
|
||||
</Space>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{message.role === "assistant" ? (
|
||||
<div className="relative">
|
||||
{editingMessageId === message.id ? (
|
||||
<div className="rounded-lg border border-blue-200">
|
||||
<Editor
|
||||
height="300px"
|
||||
defaultLanguage="json"
|
||||
value={editingContent}
|
||||
theme="vs-light"
|
||||
options={{
|
||||
minimap: { enabled: false },
|
||||
scrollBeyondLastLine: false,
|
||||
fontSize: 14,
|
||||
lineNumbers: 'on',
|
||||
renderLineHighlight: 'none',
|
||||
roundedSelection: true,
|
||||
}}
|
||||
onChange={setEditingContent}
|
||||
onMount={(editor) => {
|
||||
editor.getModel()?.updateOptions({ tabSize: 2 });
|
||||
editor.focus();
|
||||
}}
|
||||
/>
|
||||
<div className="flex justify-end gap-2 p-2 bg-gray-50 border-t">
|
||||
<Button
|
||||
size="small"
|
||||
icon={<CloseOutlined />}
|
||||
onClick={handleCancelEdit}
|
||||
className="hover:bg-gray-200"
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon={<CheckOutlined />}
|
||||
onClick={handleSaveEdit}
|
||||
className="bg-blue-600 hover:bg-blue-700"
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<CodeHighlight
|
||||
code={message.content}
|
||||
language="json"
|
||||
copyLabel="复制代码"
|
||||
copiedLabel="已复制!"
|
||||
withLineNumbers
|
||||
className="rounded-lg"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-gray-700 whitespace-pre-wrap break-words">
|
||||
{message.content}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
|
||||
<div className="border-t bg-white p-4">
|
||||
<form onSubmit={handleSendMessage} className="flex gap-2">
|
||||
<Input
|
||||
value={input}
|
||||
placeholder="请输入您的问题..."
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
disabled={isLoading}
|
||||
className="flex-1 rounded-lg border-gray-300 hover:border-blue-400 focus:border-blue-600 focus:shadow-blue-100"
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
loading={isLoading}
|
||||
className="rounded-lg bg-blue-600 hover:bg-blue-700"
|
||||
>
|
||||
发送
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user