- {messageStatus === 'loading'
- ? renderLoading()
- : messageStatus === 'failed'
- ? renderError()
- : messages.length === 0
- ? renderEmpty()
- : messages.map((message) => (
-
);
diff --git a/src/pages/Chat/NewChat.jsx b/src/pages/Chat/NewChat.jsx
index fd558c7..c725172 100644
--- a/src/pages/Chat/NewChat.jsx
+++ b/src/pages/Chat/NewChat.jsx
@@ -25,9 +25,9 @@ export default function NewChat() {
const error = useSelector((state) => state.chat.availableDatasets.error);
// 获取聊天历史记录
- const chatHistory = useSelector((state) => state.chat.history.items || []);
- const chatHistoryLoading = useSelector((state) => state.chat.history.status === 'loading');
- const chatCreationStatus = useSelector((state) => state.chat.sendMessage?.status);
+ const chatHistory = useSelector((state) => state.chat.chats.items || []);
+ const chatHistoryLoading = useSelector((state) => state.chat.chats.status === 'loading');
+ const chatCreationStatus = useSelector((state) => state.chat.messageOperation?.status);
// Gmail集成状态
const gmailSetupStatus = useSelector((state) => state.gmailChat?.setup?.status);
diff --git a/src/pages/KnowledgeBase/KnowledgeBase.jsx b/src/pages/KnowledgeBase/KnowledgeBase.jsx
index 4f4a15b..42945c9 100644
--- a/src/pages/KnowledgeBase/KnowledgeBase.jsx
+++ b/src/pages/KnowledgeBase/KnowledgeBase.jsx
@@ -15,7 +15,6 @@ import AccessRequestModal from '../../components/AccessRequestModal';
import CreateKnowledgeBaseModal from '../../components/CreateKnowledgeBaseModal';
import Pagination from '../../components/Pagination';
import SearchBar from '../../components/SearchBar';
-import ApiModeSwitch from '../../components/ApiModeSwitch';
// 导入拆分的组件
import KnowledgeBaseList from './components/KnowledgeBaseList';
@@ -461,9 +460,6 @@ export default function KnowledgeBase() {
return (
- {/*
*/}
{
- // 处理服务器无法连接的情况
- if (!error.response || error.code === 'ECONNABORTED' || error.message.includes('Network Error')) {
- console.error('Server appears to be down. Switching to mock data.');
- isServerDown = true;
- hasCheckedServer = true;
- }
-
// Handle errors in the response
if (error.response) {
// monitor /verify
@@ -74,52 +66,20 @@ api.interceptors.response.use(
}
);
-// 检查服务器状态
-export const checkServerStatus = async () => {
- try {
- // await api.get('/health-check', { timeout: 3000 });
- isServerDown = false;
- hasCheckedServer = true;
- console.log('Server connection established');
- return true;
- } catch (error) {
- isServerDown = true;
- hasCheckedServer = true;
- console.error('Server connection failed, using mock data');
- return false;
- }
-};
-// 初始检查服务器状态
-checkServerStatus();
-
-// Define common HTTP methods with fallback to mock API
+// Define common HTTP methods
const get = async (url, params = {}) => {
try {
- if (isServerDown) {
- console.log(`[MOCK MODE] GET ${url}`);
- return await mockGet(url, params);
- }
-
const res = await api.get(url, { ...params });
return res.data;
} catch (error) {
- if (!hasCheckedServer || (error.request && !error.response)) {
- console.log(`Failed to connect to server. Falling back to mock API for GET ${url}`);
- return await mockGet(url, params);
- }
throw error;
}
};
-// Handle POST requests for JSON data with fallback to mock API
+// Handle POST requests for JSON data
const post = async (url, data, isMultipart = false) => {
try {
- if (isServerDown) {
- console.log(`[MOCK MODE] POST ${url}`);
- return await mockPost(url, data);
- }
-
const headers = isMultipart
? { 'Content-Type': 'multipart/form-data' } // For file uploads
: { 'Content-Type': 'application/json' }; // For JSON data
@@ -127,61 +87,34 @@ const post = async (url, data, isMultipart = false) => {
const res = await api.post(url, data, { headers });
return res.data;
} catch (error) {
- if (!hasCheckedServer || (error.request && !error.response)) {
- console.log(`Failed to connect to server. Falling back to mock API for POST ${url}`);
- return await mockPost(url, data);
- }
throw error;
}
};
-// Handle PUT requests with fallback to mock API
+// Handle PUT requests
const put = async (url, data) => {
try {
- if (isServerDown) {
- console.log(`[MOCK MODE] PUT ${url}`);
- return await mockPut(url, data);
- }
-
const res = await api.put(url, data, {
headers: { 'Content-Type': 'application/json' },
});
return res.data;
} catch (error) {
- if (!hasCheckedServer || (error.request && !error.response)) {
- console.log(`Failed to connect to server. Falling back to mock API for PUT ${url}`);
- return await mockPut(url, data);
- }
throw error;
}
};
-// Handle DELETE requests with fallback to mock API
+// Handle DELETE requests
const del = async (url) => {
try {
- if (isServerDown) {
- console.log(`[MOCK MODE] DELETE ${url}`);
- return await mockDelete(url);
- }
-
const res = await api.delete(url);
return res.data;
} catch (error) {
- if (!hasCheckedServer || (error.request && !error.response)) {
- console.log(`Failed to connect to server. Falling back to mock API for DELETE ${url}`);
- return await mockDelete(url);
- }
throw error;
}
};
const upload = async (url, data) => {
try {
- if (isServerDown) {
- console.log(`[MOCK MODE] Upload ${url}`);
- return await mockPost(url, data, true);
- }
-
const axiosInstance = await axios.create({
baseURL: '/api',
headers: {
@@ -191,41 +124,12 @@ const upload = async (url, data) => {
const res = await axiosInstance.post(url, data);
return res.data;
} catch (error) {
- if (!hasCheckedServer || (error.request && !error.response)) {
- console.log(`Failed to connect to server. Falling back to mock API for Upload ${url}`);
- return await mockPost(url, data, true);
- }
throw error;
}
};
-
-// 手动切换到模拟API(为调试目的)
-export const switchToMockApi = () => {
- isServerDown = true;
- hasCheckedServer = true;
- console.log('Manually switched to mock API');
-};
-
-// 手动切换回真实API
-export const switchToRealApi = async () => {
- // 重新检查服务器状态
- const isServerUp = await checkServerStatus();
- console.log(isServerUp ? 'Switched back to real API' : 'Server still down, continuing with mock API');
- return isServerUp;
-};
-
// Handle streaming requests
const streamRequest = async (url, data, onChunk, onError) => {
try {
- if (isServerDown) {
- console.log(`[MOCK MODE] STREAM ${url}`);
- // 模拟流式响应
- setTimeout(() => onChunk('{"code":200,"message":"partial","data":{"content":"这是模拟的","conversation_id":"mock-1234"}}'), 300);
- setTimeout(() => onChunk('{"code":200,"message":"partial","data":{"content":"流式","conversation_id":"mock-1234"}}'), 600);
- setTimeout(() => onChunk('{"code":200,"message":"partial","data":{"content":"响应","conversation_id":"mock-1234"}}'), 900);
- setTimeout(() => onChunk('{"code":200,"message":"partial","data":{"content":"数据","conversation_id":"mock-1234","is_end":true}}'), 1200);
- return { success: true, conversation_id: 'mock-1234' };
- }
// 获取认证Token
const encryptedToken = sessionStorage.getItem('token') || '';
diff --git a/src/services/mockApi.js b/src/services/mockApi.js
deleted file mode 100644
index 10426fc..0000000
--- a/src/services/mockApi.js
+++ /dev/null
@@ -1,1240 +0,0 @@
-// Mock API service for development without backend
-import { v4 as uuidv4 } from 'uuid';
-
-// Mock data for knowledge bases
-const mockKnowledgeBases = [
- {
- id: uuidv4(),
- user_id: 'user-001',
- name: 'Frontend Development',
- desc: 'Resources and guides for frontend development including React, Vue, and Angular',
- type: 'private',
- department: '研发部',
- group: '前端开发组',
- documents: [],
- char_length: 0,
- document_count: 0,
- external_id: uuidv4(),
- create_time: '2024-02-26T08:30:00Z',
- update_time: '2024-02-26T14:45:00Z',
- permissions: {
- can_read: true,
- can_edit: true,
- can_delete: false,
- },
- },
- {
- id: uuidv4(),
- user_id: 'user-001',
- name: 'Backend Technologies',
- desc: 'Information about backend frameworks, databases, and server configurations',
- type: 'private',
- department: '研发部',
- group: '后端开发组',
- documents: [],
- char_length: 0,
- document_count: 0,
- external_id: uuidv4(),
- create_time: '2024-02-25T10:15:00Z',
- update_time: '2024-02-26T09:20:00Z',
- permissions: {
- can_read: true,
- can_edit: true,
- can_delete: false,
- },
- },
- {
- id: 'kb-003',
- name: 'DevOps Practices',
- description: 'Best practices for CI/CD, containerization, and cloud deployment',
- created_at: '2023-11-12T15:45:00Z',
- updated_at: '2024-02-05T11:30:00Z',
- create_time: '2023-11-12T15:45:00Z',
- update_time: '2024-02-05T11:30:00Z',
- type: 'public',
- owner: {
- id: 'user-002',
- username: 'janedoe',
- email: 'jane@example.com',
- },
- document_count: 18,
- tags: ['docker', 'kubernetes', 'aws'],
- permissions: {
- can_edit: false,
- can_read: true,
- },
- },
- {
- id: 'kb-004',
- name: 'Machine Learning Fundamentals',
- description: 'Introduction to machine learning concepts, algorithms, and frameworks',
- created_at: '2023-08-20T09:00:00Z',
- updated_at: '2024-01-25T16:15:00Z',
- create_time: '2023-08-20T09:00:00Z',
- update_time: '2024-01-25T16:15:00Z',
- type: 'public',
- owner: {
- id: 'user-003',
- username: 'alexsmith',
- email: 'alex@example.com',
- },
- document_count: 30,
- tags: ['ml', 'python', 'tensorflow'],
- permissions: {
- can_edit: false,
- can_read: true,
- },
- },
- {
- id: 'kb-005',
- name: 'UI/UX Design Principles',
- description: 'Guidelines for creating effective and user-friendly interfaces',
- created_at: '2023-12-01T13:20:00Z',
- updated_at: '2024-02-15T10:45:00Z',
- create_time: '2023-12-01T13:20:00Z',
- update_time: '2024-02-15T10:45:00Z',
- type: 'private',
- owner: {
- id: 'user-002',
- username: 'janedoe',
- email: 'jane@example.com',
- },
- document_count: 12,
- tags: ['design', 'ui', 'ux'],
- permissions: {
- can_edit: true,
- can_read: true,
- },
- },
- {
- id: 'kb-006',
- name: 'Mobile App Development',
- description: 'Resources for iOS, Android, and cross-platform mobile development',
- created_at: '2023-10-25T11:10:00Z',
- updated_at: '2024-01-30T14:00:00Z',
- create_time: '2023-10-25T11:10:00Z',
- update_time: '2024-01-30T14:00:00Z',
- type: 'private',
- owner: {
- id: 'user-001',
- username: 'johndoe',
- email: 'john@example.com',
- },
- document_count: 20,
- tags: ['mobile', 'react-native', 'flutter'],
- permissions: {
- can_edit: true,
- can_read: true,
- },
- },
- {
- id: 'kb-007',
- name: 'Cybersecurity Best Practices',
- description: 'Guidelines for securing applications, networks, and data',
- created_at: '2023-09-18T14:30:00Z',
- updated_at: '2024-02-10T09:15:00Z',
- create_time: '2023-09-18T14:30:00Z',
- update_time: '2024-02-10T09:15:00Z',
- type: 'private',
- owner: {
- id: 'user-004',
- username: 'sarahwilson',
- email: 'sarah@example.com',
- },
- document_count: 25,
- tags: ['security', 'encryption', 'authentication'],
- permissions: {
- can_edit: false,
- can_read: false,
- },
- },
- {
- id: 'kb-008',
- name: 'Data Science Toolkit',
- description: 'Tools and techniques for data analysis, visualization, and modeling',
- created_at: '2023-11-05T10:00:00Z',
- updated_at: '2024-01-20T15:30:00Z',
- create_time: '2023-11-05T10:00:00Z',
- update_time: '2024-01-20T15:30:00Z',
- type: 'public',
- owner: {
- id: 'user-003',
- username: 'alexsmith',
- email: 'alex@example.com',
- },
- document_count: 28,
- tags: ['data-science', 'python', 'visualization'],
- permissions: {
- can_edit: false,
- can_read: true,
- },
- },
-];
-
-// In-memory store for CRUD operations
-let knowledgeBases = [...mockKnowledgeBases];
-
-// Mock user data for authentication
-const mockUsers = [
- {
- id: 'user-001',
- username: 'leader2',
- password: 'leader123', // 在实际应用中不应该存储明文密码
- email: 'admin@example.com',
- name: '管理员',
- department: '研发部',
- group: '前端开发组',
- role: 'admin',
- avatar: null,
- created_at: '2024-01-01T00:00:00Z',
- updated_at: '2024-01-01T00:00:00Z',
- },
- {
- id: 'user-002',
- username: 'user',
- password: 'user123', // 在实际应用中不应该存储明文密码
- email: 'user@example.com',
- name: '普通用户',
- department: '市场部',
- group: '市场组',
- role: 'user',
- avatar: null,
- created_at: '2024-01-02T00:00:00Z',
- updated_at: '2024-01-02T00:00:00Z',
- },
-];
-
-// Helper function for pagination
-const paginate = (array, page_size, page) => {
- const startIndex = (page - 1) * page_size;
- const endIndex = startIndex + page_size;
- const items = array.slice(startIndex, endIndex);
-
- return {
- items,
- total: array.length,
- page,
- page_size,
- };
-};
-
-// Mock chat history data
-const mockChatHistory = [
- {
- id: 'chat-001',
- title: '关于React组件开发的问题',
- knowledge_base_id: 'kb-001',
- knowledge_base_name: 'Frontend Development',
- message_count: 5,
- created_at: '2024-03-15T10:30:00Z',
- updated_at: '2024-03-15T11:45:00Z',
- },
- {
- id: 'chat-002',
- title: 'Vue.js性能优化讨论',
- knowledge_base_id: 'kb-001',
- knowledge_base_name: 'Frontend Development',
- message_count: 3,
- created_at: '2024-03-14T15:20:00Z',
- updated_at: '2024-03-14T16:10:00Z',
- },
- {
- id: 'chat-003',
- title: '后端API集成问题',
- knowledge_base_id: 'kb-002',
- knowledge_base_name: 'Backend Technologies',
- message_count: 4,
- created_at: '2024-03-13T09:15:00Z',
- updated_at: '2024-03-13T10:30:00Z',
- },
-];
-
-// Mock chat history functions
-const mockGetChatHistory = (params) => {
- const { page = 1, page_size = 10 } = params;
- return paginate(mockChatHistory, page_size, page);
-};
-
-const mockCreateChat = (data) => {
- const newChat = {
- id: `chat-${uuidv4().slice(0, 8)}`,
- title: data.title || '新对话',
- knowledge_base_id: data.knowledge_base_id,
- knowledge_base_name: data.knowledge_base_name,
- message_count: 0,
- created_at: new Date().toISOString(),
- updated_at: new Date().toISOString(),
- };
- mockChatHistory.unshift(newChat);
- return newChat;
-};
-
-const mockUpdateChat = (id, data) => {
- const index = mockChatHistory.findIndex((chat) => chat.id === id);
- if (index === -1) {
- throw new Error('Chat not found');
- }
- const updatedChat = {
- ...mockChatHistory[index],
- ...data,
- updated_at: new Date().toISOString(),
- };
- mockChatHistory[index] = updatedChat;
- return updatedChat;
-};
-
-const mockDeleteChat = (id) => {
- const index = mockChatHistory.findIndex((chat) => chat.id === id);
- if (index === -1) {
- throw new Error('Chat not found');
- }
- mockChatHistory.splice(index, 1);
- return { success: true };
-};
-
-// 模拟聊天消息数据
-const chatMessages = {};
-
-// 权限申请列表的 mock 数据
-const mockPendingRequests = [
- {
- id: 1,
- knowledge_base: 'f13c4bdb-eb03-4ce2-b83c-30917351fb72',
- applicant: 'f2799611-7a3d-436d-b3fa-3789bdd877e2',
- permissions: {
- can_edit: false,
- can_read: true,
- can_delete: false,
- },
- status: 'pending',
- reason: '需要访问知识库进行学习',
- response_message: null,
- expires_at: '2025-03-19T00:17:43.781000Z',
- created_at: '2025-03-12T00:17:44.044351Z',
- updated_at: '2025-03-12T00:17:44.044369Z',
- },
- {
- id: 2,
- knowledge_base: 'f13c4bdb-eb03-4ce2-b83c-30917351fb73',
- applicant: 'f2799611-7a3d-436d-b3fa-3789bdd877e3',
- permissions: {
- can_edit: true,
- can_read: true,
- can_delete: false,
- },
- status: 'pending',
- reason: '需要编辑和更新文档',
- response_message: null,
- expires_at: '2025-03-20T00:17:43.781000Z',
- created_at: '2025-03-12T00:17:44.044351Z',
- updated_at: '2025-03-12T00:17:44.044369Z',
- },
-];
-
-// 用户权限列表的 mock 数据
-const mockUserPermissions = [
- {
- id: 'perm-001',
- user: {
- id: 'user-001',
- username: 'johndoe',
- name: 'John Doe',
- email: 'john@example.com',
- department: '研发部',
- group: '前端开发组',
- },
- knowledge_base: {
- id: 'kb-001',
- name: 'Frontend Development Guide',
- },
- permissions: {
- can_read: true,
- can_edit: true,
- can_delete: true,
- can_manage: true,
- },
- granted_at: '2024-01-15T10:00:00Z',
- granted_by: {
- id: 'user-admin',
- username: 'admin',
- name: 'System Admin',
- },
- },
- {
- id: 'perm-002',
- user: {
- id: 'user-002',
- username: 'janedoe',
- name: 'Jane Doe',
- email: 'jane@example.com',
- department: '研发部',
- group: '前端开发组',
- },
- knowledge_base: {
- id: 'kb-001',
- name: 'Frontend Development Guide',
- },
- permissions: {
- can_read: true,
- can_edit: true,
- can_delete: false,
- can_manage: false,
- },
- granted_at: '2024-01-20T14:30:00Z',
- granted_by: {
- id: 'user-001',
- username: 'johndoe',
- name: 'John Doe',
- },
- },
- {
- id: 'perm-003',
- user: {
- id: 'user-003',
- username: 'alexsmith',
- name: 'Alex Smith',
- email: 'alex@example.com',
- department: '研发部',
- group: '后端开发组',
- },
- knowledge_base: {
- id: 'kb-001',
- name: 'Frontend Development Guide',
- },
- permissions: {
- can_read: true,
- can_edit: false,
- can_delete: false,
- can_manage: false,
- },
- granted_at: '2024-02-01T09:15:00Z',
- granted_by: {
- id: 'user-001',
- username: 'johndoe',
- name: 'John Doe',
- },
- },
-];
-
-// Mock API handlers for permissions
-const mockPermissionApi = {
- // 获取待处理的权限申请列表
- getPendingRequests: () => {
- return {
- code: 200,
- message: 'success',
- data: {
- items: mockPendingRequests,
- total: mockPendingRequests.length,
- },
- };
- },
-
- // 获取用户权限列表
- getUserPermissions: (knowledgeBaseId) => {
- const permissions = mockUserPermissions.filter((perm) => perm.knowledge_base.id === knowledgeBaseId);
- return {
- code: 200,
- message: 'success',
- data: {
- items: permissions,
- total: permissions.length,
- },
- };
- },
-
- // 处理权限申请
- handlePermissionRequest: (requestId, action) => {
- const request = mockPendingRequests.find((req) => req.id === requestId);
- if (!request) {
- return {
- code: 404,
- message: 'Permission request not found',
- };
- }
-
- request.status = action === 'approve' ? 'approved' : 'rejected';
-
- if (action === 'approve') {
- // 如果批准,添加新的权限记录
- const newPermission = {
- id: `perm-${Date.now()}`,
- user: request.user,
- knowledge_base: request.knowledge_base,
- permissions: {
- can_read: true,
- can_edit: request.request_type === 'edit',
- can_delete: false,
- can_manage: false,
- },
- granted_at: new Date().toISOString(),
- granted_by: mockCurrentUser,
- };
- mockUserPermissions.push(newPermission);
- }
-
- return {
- code: 200,
- message: 'success',
- data: request,
- };
- },
-
- // 更新用户权限
- updateUserPermission: (permissionId, permissions) => {
- const permission = mockUserPermissions.find((perm) => perm.id === permissionId);
- if (!permission) {
- return {
- code: 404,
- message: 'Permission not found',
- };
- }
-
- permission.permissions = {
- ...permission.permissions,
- ...permissions,
- };
-
- return {
- code: 200,
- message: 'success',
- data: permission,
- };
- },
-
- // 删除用户权限
- deleteUserPermission: (permissionId) => {
- const index = mockUserPermissions.findIndex((perm) => perm.id === permissionId);
- if (index === -1) {
- return {
- code: 404,
- message: 'Permission not found',
- };
- }
-
- mockUserPermissions.splice(index, 1);
-
- return {
- code: 200,
- message: 'success',
- };
- },
-};
-
-// Mock notifications data
-const mockNotifications = [
- {
- id: "7e383fe6-6776-4609-bfd2-76446593b3b8",
- type: "permission_approved",
- icon: "bi-shield-check",
- title: "权限申请已通过",
- content: "您对知识库 '管理员个人' 的权限申请已通过",
- sender: "a9fa3c33-ca28-4ff1-b0ce-49adf0ec66f3",
- receiver: "33cc280f-7bc6-4eff-b789-8434bb8c1f78",
- is_read: false,
- related_resource: "1",
- created_at: "2025-04-12T04:49:51.724411",
- hasDetail: true,
- time: "1小时前"
- },
- {
- id: "cad476f6-1b0c-49c3-b36f-5404debf9bc2",
- type: "permission_updated",
- icon: "bi-shield",
- title: "知识库权限更新",
- content: "管理员已更新您对知识库 '测试' 的权限",
- sender: "a9fa3c33-ca28-4ff1-b0ce-49adf0ec66f3",
- receiver: "33cc280f-7bc6-4eff-b789-8434bb8c1f78",
- is_read: false,
- related_resource: "29",
- created_at: "2025-04-12T04:36:43.851494",
- hasDetail: true,
- time: "2小时前"
- },
- {
- id: uuidv4(),
- type: "system",
- icon: "bi-info-circle",
- title: "系统更新通知",
- content: "系统将在今晚22:00-23:00进行维护更新,请提前保存您的工作",
- sender: "system",
- receiver: "all",
- is_read: true,
- related_resource: null,
- created_at: "2025-04-11T14:30:00.000000",
- hasDetail: false,
- time: "1天前"
- }
-];
-
-let notifications = [...mockNotifications];
-
-// Mock API functions
-export const mockGet = async (url, params = {}) => {
- console.log(`[MOCK API] GET ${url}`, params);
-
- // Simulate network delay
- await new Promise((resolve) => setTimeout(resolve, 500));
-
- // Get current user
- if (url === '/users/me/') {
- return {
- user: mockUsers[0], // 默认返回第一个用户
- };
- }
-
- // Get knowledge bases
- if (url === '/knowledge-bases/') {
- const result = paginate(knowledgeBases, params.page_size, params.page);
-
- return {
- data: {
- code: 200,
- message: '获取知识库列表成功',
- data: {
- total: result.total,
- page: result.page,
- page_size: result.page_size,
- items: result.items,
- },
- },
- };
- }
-
- // Get knowledge base details
- if (url.match(/^\/knowledge-bases\/[^/]+\/$/)) {
- const id = url.split('/')[2];
- const knowledgeBase = knowledgeBases.find((kb) => kb.id === id);
-
- if (!knowledgeBase) {
- throw { response: { status: 404, data: { message: 'Knowledge base not found' } } };
- }
-
- return {
- data: {
- code: 200,
- message: 'success',
- data: {
- knowledge_base: knowledgeBase,
- },
- },
- };
- }
-
- // Get chat history
- if (url === '/chat-history/') {
- const result = mockGetChatHistory(params);
- return {
- data: {
- code: 200,
- message: 'success',
- data: result,
- },
- };
- }
-
- // Get chat messages
- if (url.match(/^\/chat-history\/[^/]+\/messages\/$/)) {
- const chatId = url.split('/')[2];
-
- // 如果没有该聊天的消息记录,创建一个空数组
- if (!chatMessages[chatId]) {
- chatMessages[chatId] = [];
-
- // 添加一条欢迎消息
- const chat = mockChatHistory.find((chat) => chat.id === chatId);
- if (chat) {
- chatMessages[chatId].push({
- id: uuidv4(),
- chat_id: chatId,
- sender: 'bot',
- content: `欢迎使用 ${chat.knowledge_base_name},有什么可以帮助您的?`,
- type: 'text',
- created_at: new Date().toISOString(),
- });
- }
- }
-
- return {
- code: 200,
- message: '获取成功',
- data: {
- messages: chatMessages[chatId] || [],
- },
- };
- }
-
- // Knowledge base search
- if (url === '/knowledge-bases/search/') {
- const { keyword = '', page = 1, page_size = 10 } = params.params || {};
- const filtered = knowledgeBases.filter(
- (kb) =>
- kb.name.toLowerCase().includes(keyword.toLowerCase()) ||
- kb.description.toLowerCase().includes(keyword.toLowerCase()) ||
- kb.tags.some((tag) => tag.toLowerCase().includes(keyword.toLowerCase()))
- );
- const result = paginate(filtered, page_size, page);
- return {
- code: 200,
- message: 'success',
- data: result,
- };
- }
-
- // 用户权限管理 - 获取用户列表
- if (url === '/users/permissions/') {
- return {
- code: 200,
- message: 'success',
- data: {
- users: mockUsers,
- },
- };
- }
-
- // 用户权限管理 - 获取待处理申请
- if (url === '/permissions/pending/') {
- return {
- code: 200,
- message: 'success',
- data: {
- items: mockPendingRequests,
- total: mockPendingRequests.length,
- },
- };
- }
-
- // 用户权限管理 - 获取用户权限详情
- if (url.match(/\/users\/(.+)\/permissions\//)) {
- const userId = url.match(/\/users\/(.+)\/permissions\//)[1];
-
- return {
- code: 200,
- message: 'success',
- data: {
- permissions: mockUserPermissions[userId] || [],
- },
- };
- }
-
- // 获取知识库文档列表
- if (url.match(/\/knowledge-bases\/([^/]+)\/documents\//)) {
- const knowledge_base_id = url.match(/\/knowledge-bases\/([^/]+)\/documents\//)[1];
- const page = params?.params?.page || 1;
- const page_size = params?.params?.page_size || 10;
-
- // 模拟文档列表数据
- const mockDocuments = [
- {
- id: 'df6d2c2b-895c-4c56-83c8-1644345e654d',
- document_id: '772044ae-0ecf-11f0-8082-0242ac120002',
- document_name: '产品说明书.pdf',
- external_id: '772044ae-0ecf-11f0-8082-0242ac120002',
- create_time: '2023-04-01 08:01:06',
- update_time: '2023-04-01 08:01:06',
- },
- {
- id: 'eba8f519-debf-461c-b4fd-87177d94bece',
- document_id: '429a2c08-0ea3-11f0-bdec-0242ac120002',
- document_name: '用户手册.docx',
- external_id: '429a2c08-0ea3-11f0-bdec-0242ac120002',
- create_time: '2023-04-01 02:44:38',
- update_time: '2023-04-01 02:44:38',
- },
- {
- id: '7a9e4c31-5b2d-437e-9a8f-2b5c7e8a9d1e',
- document_id: 'c9a8f2b5-7e8a-9d1e-7a9e-4c315b2d437e',
- document_name: '技术文档.txt',
- external_id: 'c9a8f2b5-7e8a-9d1e-7a9e-4c315b2d437e',
- create_time: '2023-03-15 10:23:45',
- update_time: '2023-03-15 10:23:45',
- },
- ];
-
- return {
- data: {
- code: 200,
- message: '获取文档列表成功',
- data: {
- total: mockDocuments.length,
- page: page,
- page_size: page_size,
- items: mockDocuments,
- },
- },
- };
- }
-
- // Notifications API
- if (url === '/notifications/') {
- await mockDelay();
- return [...notifications];
- }
-
- // Default case (if no other match)
- console.warn(`Mock GET for ${url} not implemented`);
- return { code: 404, message: 'Not found', data: null };
-};
-
-export const mockPost = async (url, data, isMultipart = false) => {
- console.log(`[MOCK API] POST ${url}`, data);
-
- // Simulate network delay
- await new Promise((resolve) => setTimeout(resolve, 800));
-
- // Login
- if (url === '/auth/login/') {
- const { username, password } = data;
- const user = mockUsers.find((u) => u.username === username && u.password === password);
-
- if (!user) {
- throw {
- response: {
- status: 401,
- data: {
- code: 401,
- message: '用户名或密码错误',
- },
- },
- };
- }
-
- // 在实际应用中,这里应该生成 JWT token
- const token = `mock-jwt-token-${uuidv4()}`;
-
- return {
- code: 200,
- message: '登录成功',
- data: {
- token,
- id: user.id,
- username: user.username,
- email: user.email,
- name: user.name,
- department: user.department,
- group: user.group,
- role: user.role,
- avatar: user.avatar,
- },
- };
- }
-
- // Create knowledge base
- if (url === '/knowledge-bases/') {
- const newKnowledgeBase = {
- id: `kb-${uuidv4().slice(0, 8)}`,
- name: data.name,
- description: data.description || '',
- desc: data.desc || data.description || '',
- created_at: new Date().toISOString(),
- updated_at: new Date().toISOString(),
- create_time: new Date().toISOString(),
- update_time: new Date().toISOString(),
- type: data.type || 'private',
- department: data.department || null,
- group: data.group || null,
- owner: {
- id: 'user-001',
- username: 'johndoe',
- email: 'john@example.com',
- },
- document_count: 0,
- tags: data.tags || [],
- permissions: {
- can_edit: true,
- can_read: true,
- },
- documents: [],
- };
-
- knowledgeBases.push(newKnowledgeBase);
-
- return {
- code: 200,
- message: '知识库创建成功',
- data: {
- knowledge_base: newKnowledgeBase,
- external_id: uuidv4(),
- },
- };
- }
-
- // Create new chat
- if (url === '/chat-history/') {
- const newChat = mockCreateChat(data);
- return {
- code: 200,
- message: 'success',
- data: {
- chat: newChat,
- },
- };
- }
-
- // Send chat message
- if (url.match(/^\/chat-history\/[^/]+\/messages\/$/)) {
- const chatId = url.split('/')[2];
-
- // 如果没有该聊天的消息记录,创建一个空数组
- if (!chatMessages[chatId]) {
- chatMessages[chatId] = [];
- }
-
- // 创建用户消息
- const userMessage = {
- id: uuidv4(),
- chat_id: chatId,
- sender: 'user',
- content: data.content,
- type: data.type || 'text',
- created_at: new Date().toISOString(),
- };
-
- // 添加用户消息
- chatMessages[chatId].push(userMessage);
-
- // 创建机器人回复
- const botMessage = {
- id: uuidv4(),
- chat_id: chatId,
- sender: 'bot',
- content: `这是对您问题的回复:${data.content}`,
- type: 'text',
- created_at: new Date(Date.now() + 1000).toISOString(),
- };
-
- // 添加机器人回复
- chatMessages[chatId].push(botMessage);
-
- // 更新聊天的最后一条消息和时间
- const chatIndex = mockChatHistory.findIndex((chat) => chat.id === chatId);
- if (chatIndex !== -1) {
- mockChatHistory[chatIndex].message_count = (mockChatHistory[chatIndex].message_count || 0) + 2;
- mockChatHistory[chatIndex].updated_at = new Date().toISOString();
- }
-
- return {
- code: 200,
- message: '发送成功',
- data: {
- user_message: userMessage,
- bot_message: botMessage,
- },
- };
- }
-
- // 批准权限申请
- if (url === '/permissions/approve/') {
- const { id, responseMessage } = data;
-
- // 从待处理列表中移除该申请
- mockPendingRequests = mockPendingRequests.filter((request) => request.id !== id);
-
- return {
- code: 200,
- message: 'Permission approved successfully',
- data: {
- id: id,
- status: 'approved',
- response_message: responseMessage,
- },
- };
- }
-
- // 创建会话 (不发送消息)
- if (url === '/chat-history/create_conversation') {
- const { dataset_id_list } = data;
-
- // 生成新的会话ID
- const conversation_id = `conv-${uuidv4()}`;
-
- console.log(`[MOCK API] 创建新会话: ${conversation_id}, 知识库: ${dataset_id_list.join(', ')}`);
-
- return {
- code: 200,
- message: '会话创建成功',
- data: {
- conversation_id: conversation_id,
- dataset_id_list: dataset_id_list,
- },
- };
- }
-
- // 拒绝权限申请
- if (url === '/permissions/reject/') {
- const { id, responseMessage } = data;
-
- // 从待处理列表中移除该申请
- mockPendingRequests = mockPendingRequests.filter((request) => request.id !== id);
-
- return {
- code: 200,
- message: 'Permission rejected successfully',
- data: {
- id: id,
- status: 'rejected',
- response_message: responseMessage,
- },
- };
- }
-
- // 上传知识库文档
- if (url.match(/\/knowledge-bases\/([^/]+)\/upload_document\//)) {
- const knowledge_base_id = url.match(/\/knowledge-bases\/([^/]+)\/upload_document\//)[1];
- const file = isMultipart ? data.get('file') : null;
-
- return {
- data: {
- code: 200,
- message: 'Document uploaded successfully',
- data: {
- id: `doc-${Date.now()}`,
- knowledge_base_id: knowledge_base_id,
- filename: file ? file.name : 'mock-document.pdf',
- status: 'processing',
- created_at: new Date().toISOString(),
- },
- },
- };
- }
-
- // Mark all notifications as read
- if (url === '/notifications/mark-all-as-read/') {
- // Update all notifications to be read
- notifications.forEach(notification => {
- notification.is_read = true;
- });
-
- return {
- code: 200,
- message: 'All notifications marked as read successfully',
- data: { success: true }
- };
- }
-
- // Mark a notification as read
- if (url.match(/\/notifications\/([^\/]+)\/mark-as-read\//)) {
- const notificationId = url.match(/\/notifications\/([^\/]+)\/mark-as-read\//)[1];
- const notificationIndex = notifications.findIndex(n => n.id === notificationId);
-
- if (notificationIndex !== -1) {
- notifications[notificationIndex] = {
- ...notifications[notificationIndex],
- is_read: true
- };
- return {
- code: 200,
- message: 'Notification marked as read successfully',
- data: { success: true, notification: notifications[notificationIndex] }
- };
- }
-
- return { code: 404, message: 'Notification not found', data: null };
- }
-
- throw { response: { status: 404, data: { message: 'Not found' } } };
-};
-
-export const mockPut = async (url, data) => {
- console.log('Mock PUT:', url, data);
- await mockDelay();
-
- // Simulate network delay
- await new Promise((resolve) => setTimeout(resolve, 600));
-
- // Update knowledge base
- if (url.match(/^\/knowledge-bases\/[^/]+\/$/)) {
- const id = url.split('/')[2];
- const index = knowledgeBases.findIndex((kb) => kb.id === id);
-
- if (index === -1) {
- throw { response: { status: 404, data: { message: 'Knowledge base not found' } } };
- }
-
- const updatedKnowledgeBase = {
- ...knowledgeBases[index],
- ...data,
- updated_at: new Date().toISOString(),
- update_time: new Date().toISOString(),
- };
-
- knowledgeBases[index] = updatedKnowledgeBase;
-
- // 返回与 mockPost 类似的格式
- return {
- code: 200,
- message: '知识库更新成功',
- data: {
- knowledge_base: updatedKnowledgeBase,
- external_id: knowledgeBases[index].id,
- },
- };
- }
-
- // Update chat
- if (url.match(/^\/chat-history\/[^/]+\/$/)) {
- const id = url.split('/')[2];
- return { data: mockUpdateChat(id, data) };
- }
-
- // 更新用户权限
- if (url.match(/\/users\/(.+)\/permissions\//)) {
- const userId = url.match(/\/users\/(.+)\/permissions\//)[1];
- const { permissions } = data;
-
- // 将权限更新应用到模拟数据
- if (mockUserPermissions[userId]) {
- // 遍历permissions对象,更新对应知识库的权限
- Object.entries(permissions).forEach(([knowledgeBaseId, permissionType]) => {
- // 查找该用户的该知识库权限
- const permissionIndex = mockUserPermissions[userId].findIndex(
- (p) => p.knowledge_base.id === knowledgeBaseId
- );
-
- if (permissionIndex !== -1) {
- // 根据权限类型设置具体权限
- const permission = {
- can_read: permissionType === 'read' || permissionType === 'edit' || permissionType === 'admin',
- can_edit: permissionType === 'edit' || permissionType === 'admin',
- can_admin: permissionType === 'admin',
- };
-
- // 更新权限
- mockUserPermissions[userId][permissionIndex].permission = permission;
- }
- });
- }
-
- return {
- code: 200,
- message: 'Permissions updated successfully',
- data: {
- permissions: permissions,
- },
- };
- }
-
- // Mark notification as read
- if (url.match(/\/notifications\/([^\/]+)\/read/)) {
- const notificationId = url.match(/\/notifications\/([^\/]+)\/read/)[1];
- const notificationIndex = notifications.findIndex(n => n.id === notificationId);
-
- if (notificationIndex !== -1) {
- notifications[notificationIndex] = {
- ...notifications[notificationIndex],
- is_read: true
- };
- return { success: true, notification: notifications[notificationIndex] };
- }
-
- return { code: 404, message: 'Notification not found', data: null };
- }
-
- // Default case
- console.warn(`Mock PUT for ${url} not implemented`);
- return { code: 404, message: 'Not found', data: null };
-};
-
-export const mockDelete = async (url) => {
- console.log(`[MOCK API] DELETE ${url}`);
-
- // Simulate network delay
- await new Promise((resolve) => setTimeout(resolve, 800));
-
- // Delete knowledge base
- if (url.match(/^\/knowledge-bases\/[^/]+\/$/)) {
- const id = url.split('/')[2];
- const index = knowledgeBases.findIndex((kb) => kb.id === id);
-
- if (index === -1) {
- throw { response: { status: 404, data: { message: 'Knowledge base not found' } } };
- }
-
- knowledgeBases.splice(index, 1);
- return { success: true };
- }
-
- // Delete chat (new endpoint)
- if (url.match(/^\/chat-history\/delete_conversation/)) {
- const params = new URLSearchParams(url.split('?')[1]);
- const conversationId = params.get('conversation_id');
-
- if (!conversationId) {
- throw { response: { status: 400, data: { message: 'Missing conversation_id parameter' } } };
- }
-
- console.log(`[MOCK API] Deleting conversation: ${conversationId}`);
-
- // 查找并删除会话
- const index = mockChatHistory.findIndex(
- (chat) => chat.id === conversationId || chat.conversation_id === conversationId
- );
-
- if (index === -1) {
- // 即使找不到也返回成功,保持与API一致的行为
- console.log(`[MOCK API] Conversation not found: ${conversationId}, but returning success`);
- return {
- code: 200,
- message: '会话删除成功',
- data: {},
- };
- }
-
- mockChatHistory.splice(index, 1);
-
- // 清除会话消息
- if (chatMessages[conversationId]) {
- delete chatMessages[conversationId];
- }
-
- return {
- code: 200,
- message: '会话删除成功',
- data: {},
- };
- }
-
- // Delete chat (old endpoint - keeping for backward compatibility)
- if (url.match(/^\/chat-history\/[^/]+\/$/)) {
- const id = url.split('/')[2];
- return { data: mockDeleteChat(id) };
- }
-
- // 删除知识库文档
- if (url.match(/\/knowledge-bases\/([^/]+)\/documents\/([^/]+)/)) {
- const matches = url.match(/\/knowledge-bases\/([^/]+)\/documents\/([^/]+)/);
- const knowledge_base_id = matches[1];
- const document_id = matches[2];
-
- console.log(`[MOCK API] Deleting document ${document_id} from knowledge base ${knowledge_base_id}`);
-
- return {
- data: {
- code: 200,
- message: '文档删除成功',
- },
- };
- }
-
- throw { response: { status: 404, data: { message: 'Not found' } } };
-};
-
-// Reset mock data to initial state (useful for testing)
-export const resetMockData = () => {
- knowledgeBases = [...mockKnowledgeBases];
-};
-
-// 添加权限相关的 API 处理
-export const mockApi = {
- // ... existing api handlers ...
-
- // 权限管理相关的 API
- 'GET /api/permissions/pending': () => mockPermissionApi.getPendingRequests(),
- 'GET /api/permissions/users/:knowledgeBaseId': (params) =>
- mockPermissionApi.getUserPermissions(params.knowledgeBaseId),
- 'POST /api/permissions/handle/:requestId': (params, body) =>
- mockPermissionApi.handlePermissionRequest(params.requestId, body.action),
- 'PUT /api/permissions/:permissionId': (params, body) =>
- mockPermissionApi.updateUserPermission(params.permissionId, body.permissions),
- 'DELETE /api/permissions/:permissionId': (params) => mockPermissionApi.deleteUserPermission(params.permissionId),
-};
diff --git a/src/store/chat/chat.messages.thunks.js b/src/store/chat/chat.messages.thunks.js
index 7beea0c..e6ef1a3 100644
--- a/src/store/chat/chat.messages.thunks.js
+++ b/src/store/chat/chat.messages.thunks.js
@@ -3,18 +3,20 @@ import { get, post } from '../../services/api';
/**
* 获取聊天消息
- * @param {string} chatId - 聊天ID
+ * @param {string} conversationId - 会话ID
*/
-export const fetchMessages = createAsyncThunk('chat/fetchMessages', async (chatId, { rejectWithValue }) => {
+export const fetchMessages = createAsyncThunk('chat/fetchMessages', async (conversationId, { rejectWithValue }) => {
try {
- const response = await get(`/chat-history/${chatId}/messages/`);
+ const response = await get(`/chat-history/conversation_detail`, {
+ params: { conversation_id: conversationId },
+ });
// 处理返回格式
if (response && response.code === 200) {
- return response.data.messages;
+ return response.data.messages || [];
}
- return response.data?.messages || [];
+ return [];
} catch (error) {
return rejectWithValue(error.response?.data?.message || 'Failed to fetch messages');
}
@@ -35,7 +37,10 @@ export const sendMessage = createAsyncThunk('chat/sendMessage', async ({ chatId,
// 处理返回格式
if (response && response.code === 200) {
- return response.data;
+ return {
+ ...response.data,
+ role: response.data.role || 'user', // 确保有角色字段
+ };
}
return response.data || {};
diff --git a/src/store/chat/chat.slice.js b/src/store/chat/chat.slice.js
index 890acda..3d5e8ce 100644
--- a/src/store/chat/chat.slice.js
+++ b/src/store/chat/chat.slice.js
@@ -2,7 +2,6 @@ import { createSlice } from '@reduxjs/toolkit';
import {
fetchAvailableDatasets,
fetchChats,
- createChat,
updateChat,
deleteChat,
createChatRecord,
@@ -13,28 +12,24 @@ import { fetchMessages, sendMessage } from './chat.messages.thunks';
// 初始状态
const initialState = {
- // Chat history state
- history: {
- items: [],
+ // 聊天列表,包含所有聊天及其消息
+ chats: {
+ items: [], // 每个chat对象包含conversation_id, datasets, create_time, messages等
status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
error: null,
+ pagination: {
+ total: 0,
+ page: 1,
+ page_size: 10,
+ },
},
- // Chat session creation state
- createSession: {
- status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
- error: null,
- sessionId: null,
- },
- // Chat messages state
- messages: {
- items: [],
- status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
- error: null,
- },
- // Send message state
- sendMessage: {
+ // 当前活跃聊天的ID
+ activeConversationId: null,
+ // 消息发送状态
+ messageOperation: {
status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
error: null,
+ streamingMessageId: null, // 当前正在流式传输的消息ID(如果有)
},
// 可用于聊天的知识库列表
availableDatasets: {
@@ -42,26 +37,16 @@ const initialState = {
status: 'idle',
error: null,
},
- // 操作状态(创建、更新、删除)
- operations: {
+ // 聊天操作状态(创建、更新、删除)
+ chatOperation: {
status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
error: null,
},
- // 兼容旧版本的state结构
- list: {
- items: [],
- total: 0,
- page: 1,
- page_size: 10,
- status: 'idle',
- error: null,
- },
- // 当前聊天
- currentChat: {
- data: null,
- status: 'idle',
- error: null,
- },
+};
+
+// 辅助函数:查找聊天索引
+const findChatIndex = (state, conversationId) => {
+ return state.chats.items.findIndex((chat) => chat.conversation_id === conversationId);
};
// 创建 slice
@@ -70,57 +55,98 @@ const chatSlice = createSlice({
initialState,
reducers: {
// 重置操作状态
- resetOperationStatus: (state) => {
- state.operations.status = 'idle';
- state.operations.error = null;
+ resetChatOperation: (state) => {
+ state.chatOperation.status = 'idle';
+ state.chatOperation.error = null;
},
- // 重置当前聊天
- resetCurrentChat: (state) => {
- state.currentChat.data = null;
- state.currentChat.status = 'idle';
- state.currentChat.error = null;
+ // 设置当前活跃聊天
+ setActiveChat: (state, action) => {
+ state.activeConversationId = action.payload;
},
- // 设置当前聊天
- setCurrentChat: (state, action) => {
- state.currentChat.data = action.payload;
- state.currentChat.status = 'succeeded';
+ // 重置消息操作状态
+ resetMessageOperation: (state) => {
+ state.messageOperation.status = 'idle';
+ state.messageOperation.error = null;
+ state.messageOperation.streamingMessageId = null;
},
- // 重置消息状态
- resetMessages: (state) => {
- state.messages.items = [];
- state.messages.status = 'idle';
- state.messages.error = null;
- },
-
- // 重置发送消息状态
- resetSendMessageStatus: (state) => {
- state.sendMessage.status = 'idle';
- state.sendMessage.error = null;
- },
-
- // 添加消息
+ // 添加消息到特定聊天
addMessage: (state, action) => {
- state.messages.items.push(action.payload);
+ const { conversationId, message } = action.payload;
+ const chatIndex = findChatIndex(state, conversationId);
+
+ if (chatIndex !== -1) {
+ // 确保chat有messages数组
+ if (!state.chats.items[chatIndex].messages) {
+ state.chats.items[chatIndex].messages = [];
+ }
+
+ // 添加消息
+ state.chats.items[chatIndex].messages.push(message);
+
+ // 更新最后一条消息和消息计数
+ state.chats.items[chatIndex].last_message = message.content;
+ state.chats.items[chatIndex].message_count = (state.chats.items[chatIndex].message_count || 0) + 1;
+
+ // 如果是助手消息且正在流式传输,记录ID
+ if (message.role === 'assistant' && message.is_streaming) {
+ state.messageOperation.streamingMessageId = message.id;
+ state.messageOperation.status = 'loading';
+ }
+ }
},
// 更新消息(用于流式传输)
updateMessage: (state, action) => {
- const { id, ...updates } = action.payload;
- const messageIndex = state.messages.items.findIndex((msg) => msg.id === id);
+ const { conversationId, messageId, updates, serverMessageId } = action.payload;
+ const chatIndex = findChatIndex(state, conversationId);
- if (messageIndex !== -1) {
- // 更新现有消息
- state.messages.items[messageIndex] = {
- ...state.messages.items[messageIndex],
- ...updates,
- };
+ if (chatIndex !== -1 && state.chats.items[chatIndex].messages) {
+ // 首先尝试使用服务器返回的ID找到消息
+ let messageIndex = -1;
- // 如果流式传输结束,更新发送消息状态
- if (updates.is_streaming === false) {
- state.sendMessage.status = 'succeeded';
+ if (serverMessageId) {
+ // 如果提供了服务器ID,优先使用它查找消息
+ messageIndex = state.chats.items[chatIndex].messages.findIndex(
+ (msg) => msg.id === serverMessageId || msg.server_id === serverMessageId
+ );
+ }
+
+ // 如果没找到或没提供服务器ID,则使用客户端生成的ID
+ if (messageIndex === -1) {
+ messageIndex = state.chats.items[chatIndex].messages.findIndex((msg) => msg.id === messageId);
+ }
+
+ if (messageIndex !== -1) {
+ // 更新现有消息
+ const updatedMessage = {
+ ...state.chats.items[chatIndex].messages[messageIndex],
+ ...updates,
+ };
+
+ // 如果收到了服务器ID且消息没有server_id字段,添加它
+ if (serverMessageId && !updatedMessage.server_id) {
+ updatedMessage.server_id = serverMessageId;
+ }
+
+ state.chats.items[chatIndex].messages[messageIndex] = updatedMessage;
+
+ // 如果流式传输结束,更新状态
+ if (
+ updates.is_streaming === false &&
+ (messageId === state.messageOperation.streamingMessageId ||
+ serverMessageId === state.messageOperation.streamingMessageId)
+ ) {
+ state.messageOperation.status = 'succeeded';
+ state.messageOperation.streamingMessageId = null;
+ }
+
+ // 如果更新了内容,更新最后一条消息
+ if (updates.content) {
+ state.chats.items[chatIndex].last_message = updates.content;
+ }
}
}
},
@@ -129,189 +155,161 @@ const chatSlice = createSlice({
// 获取聊天列表
builder
.addCase(fetchChats.pending, (state) => {
- state.list.status = 'loading';
- state.history.status = 'loading';
+ state.chats.status = 'loading';
})
.addCase(fetchChats.fulfilled, (state, action) => {
- state.list.status = 'succeeded';
+ state.chats.status = 'succeeded';
// 检查是否是追加模式
if (action.payload.append) {
// 追加模式:将新结果添加到现有列表的前面
- state.list.items = [...action.payload.results, ...state.list.items];
- state.history.items = [...action.payload.results, ...state.history.items];
+ state.chats.items = [...action.payload.results, ...state.chats.items];
} else {
// 替换模式:使用新结果替换整个列表
- state.list.items = action.payload.results;
- state.list.total = action.payload.total;
- state.list.page = action.payload.page;
- state.list.page_size = action.payload.page_size;
-
- // 同时更新新的状态结构
- state.history.items = action.payload.results;
+ state.chats.items = action.payload.results;
+ state.chats.pagination.total = action.payload.total;
+ state.chats.pagination.page = action.payload.page;
+ state.chats.pagination.page_size = action.payload.page_size;
}
-
- state.history.status = 'succeeded';
- state.history.error = null;
})
.addCase(fetchChats.rejected, (state, action) => {
- state.list.status = 'failed';
- state.list.error = action.payload || action.error.message;
-
- // 同时更新新的状态结构
- state.history.status = 'failed';
- state.history.error = action.payload || action.error.message;
- })
-
- // 创建聊天
- .addCase(createChat.pending, (state) => {
- state.operations.status = 'loading';
- })
- .addCase(createChat.fulfilled, (state, action) => {
- state.operations.status = 'succeeded';
- state.list.items.unshift(action.payload);
- state.list.total += 1;
- state.currentChat.data = action.payload;
- state.currentChat.status = 'succeeded';
- })
- .addCase(createChat.rejected, (state, action) => {
- state.operations.status = 'failed';
- state.operations.error = action.payload || action.error.message;
+ state.chats.status = 'failed';
+ state.chats.error = action.payload || action.error.message;
})
// 删除聊天
.addCase(deleteChat.pending, (state) => {
- state.operations.status = 'loading';
+ state.chatOperation.status = 'loading';
})
.addCase(deleteChat.fulfilled, (state, action) => {
- state.operations.status = 'succeeded';
- // 更新旧的状态结构
- state.list.items = state.list.items.filter((chat) => chat.id !== action.payload);
- // 更新新的状态结构
- state.history.items = state.history.items.filter((chat) => chat.conversation_id !== action.payload);
+ state.chatOperation.status = 'succeeded';
+ // 删除聊天
+ state.chats.items = state.chats.items.filter((chat) => chat.conversation_id !== action.payload);
- if (state.list.total > 0) {
- state.list.total -= 1;
+ if (state.chats.pagination.total > 0) {
+ state.chats.pagination.total -= 1;
}
- if (state.currentChat.data && state.currentChat.data.id === action.payload) {
- state.currentChat.data = null;
+ // 如果删除的是当前活跃聊天,重置activeConversationId
+ if (state.activeConversationId === action.payload) {
+ state.activeConversationId = null;
}
})
.addCase(deleteChat.rejected, (state, action) => {
- state.operations.status = 'failed';
- state.operations.error = action.payload || action.error.message;
+ state.chatOperation.status = 'failed';
+ state.chatOperation.error = action.payload || action.error.message;
})
// 更新聊天
.addCase(updateChat.pending, (state) => {
- state.operations.status = 'loading';
+ state.chatOperation.status = 'loading';
})
.addCase(updateChat.fulfilled, (state, action) => {
- state.operations.status = 'succeeded';
- const index = state.list.items.findIndex((chat) => chat.id === action.payload.id);
- if (index !== -1) {
- state.list.items[index] = action.payload;
- }
- if (state.currentChat.data && state.currentChat.data.id === action.payload.id) {
- state.currentChat.data = action.payload;
+ state.chatOperation.status = 'succeeded';
+ const chatIndex = findChatIndex(state, action.payload.conversation_id);
+ if (chatIndex !== -1) {
+ // 保留messages字段,避免覆盖
+ const existingMessages = state.chats.items[chatIndex].messages;
+ state.chats.items[chatIndex] = {
+ ...action.payload,
+ messages: existingMessages || [],
+ };
}
})
.addCase(updateChat.rejected, (state, action) => {
- state.operations.status = 'failed';
- state.operations.error = action.payload || action.error.message;
+ state.chatOperation.status = 'failed';
+ state.chatOperation.error = action.payload || action.error.message;
})
// 获取聊天消息
.addCase(fetchMessages.pending, (state) => {
- state.messages.status = 'loading';
- state.messages.error = null;
+ state.messageOperation.status = 'loading';
})
.addCase(fetchMessages.fulfilled, (state, action) => {
- state.messages.status = 'succeeded';
- state.messages.items = action.payload;
+ state.messageOperation.status = 'succeeded';
+ // 假设action.meta.arg是conversationId
+ const conversationId = action.meta.arg;
+ const chatIndex = findChatIndex(state, conversationId);
+
+ if (chatIndex !== -1) {
+ state.chats.items[chatIndex].messages = action.payload;
+ }
})
.addCase(fetchMessages.rejected, (state, action) => {
- state.messages.status = 'failed';
- state.messages.error = action.error.message;
+ state.messageOperation.status = 'failed';
+ state.messageOperation.error = action.error.message;
})
// 发送聊天消息
.addCase(sendMessage.pending, (state) => {
- state.sendMessage.status = 'loading';
- state.sendMessage.error = null;
+ state.messageOperation.status = 'loading';
})
.addCase(sendMessage.fulfilled, (state, action) => {
- state.sendMessage.status = 'succeeded';
- // 更新消息列表
- const index = state.messages.items.findIndex(
- (msg) => msg.content === action.payload.content && msg.sender === action.payload.sender
- );
- if (index === -1) {
- state.messages.items.push(action.payload);
+ state.messageOperation.status = 'succeeded';
+ // 假设action.meta.arg包含chatId
+ const { chatId } = action.meta.arg;
+ const chatIndex = findChatIndex(state, chatId);
+
+ if (chatIndex !== -1) {
+ // 确保chat有messages数组
+ if (!state.chats.items[chatIndex].messages) {
+ state.chats.items[chatIndex].messages = [];
+ }
+
+ // 检查消息是否已存在
+ const messageExists = state.chats.items[chatIndex].messages.some(
+ (msg) => msg.content === action.payload.content && msg.role === action.payload.role
+ );
+
+ if (!messageExists) {
+ state.chats.items[chatIndex].messages.push(action.payload);
+ state.chats.items[chatIndex].last_message = action.payload.content;
+ state.chats.items[chatIndex].message_count =
+ (state.chats.items[chatIndex].message_count || 0) + 1;
+ }
}
})
.addCase(sendMessage.rejected, (state, action) => {
- state.sendMessage.status = 'failed';
- state.sendMessage.error = action.error.message;
+ state.messageOperation.status = 'failed';
+ state.messageOperation.error = action.error.message;
})
// 处理创建聊天记录
.addCase(createChatRecord.pending, (state) => {
- state.sendMessage.status = 'loading';
- state.sendMessage.error = null;
+ state.messageOperation.status = 'loading';
})
.addCase(createChatRecord.fulfilled, (state, action) => {
- // 更新状态以反映聊天已创建
- if (action.payload.conversation_id && !state.currentChat.data) {
- // 设置当前聊天的会话ID
- state.currentChat.data = {
- conversation_id: action.payload.conversation_id,
- // 其他信息将由流式更新填充
- };
- }
- // 不再在这里添加消息,因为消息已经在thunk函数中添加
+ // 聊天创建成功,但消息状态由addMessage和updateMessage处理
+ state.activeConversationId = action.payload.conversation_id;
})
.addCase(createChatRecord.rejected, (state, action) => {
- state.sendMessage.status = 'failed';
- state.sendMessage.error = action.error.message;
+ state.messageOperation.status = 'failed';
+ state.messageOperation.error = action.error.message;
})
// 处理创建会话
.addCase(createConversation.pending, (state) => {
- state.createSession.status = 'loading';
- state.createSession.error = null;
+ state.chatOperation.status = 'loading';
})
.addCase(createConversation.fulfilled, (state, action) => {
- state.createSession.status = 'succeeded';
- state.createSession.sessionId = action.payload.conversation_id;
+ state.chatOperation.status = 'succeeded';
+ state.activeConversationId = action.payload.conversation_id;
- // 当前聊天设置 - 使用与fetchConversationDetail相同的数据结构
- state.currentChat.data = {
- conversation_id: action.payload.conversation_id,
- datasets: action.payload.datasets || [],
- // 添加其他必要的字段,确保与fetchConversationDetail返回的数据结构兼容
- messages: [],
- create_time: new Date().toISOString(),
- update_time: new Date().toISOString(),
- };
- state.currentChat.status = 'succeeded';
- state.currentChat.error = null;
+ // 在执行createConversation时,已经通过dispatch添加了新聊天到列表
+ // 所以这里只需确保当前激活的聊天ID已设置
})
.addCase(createConversation.rejected, (state, action) => {
- state.createSession.status = 'failed';
- state.createSession.error = action.payload || action.error.message;
+ state.chatOperation.status = 'failed';
+ state.chatOperation.error = action.payload || action.error.message;
})
// 处理获取可用知识库
.addCase(fetchAvailableDatasets.pending, (state) => {
state.availableDatasets.status = 'loading';
- state.availableDatasets.error = null;
})
.addCase(fetchAvailableDatasets.fulfilled, (state, action) => {
state.availableDatasets.status = 'succeeded';
state.availableDatasets.items = action.payload || [];
- state.availableDatasets.error = null;
})
.addCase(fetchAvailableDatasets.rejected, (state, action) => {
state.availableDatasets.status = 'failed';
@@ -320,35 +318,38 @@ const chatSlice = createSlice({
// 获取会话详情
.addCase(fetchConversationDetail.pending, (state) => {
- state.currentChat.status = 'loading';
- state.currentChat.error = null;
+ // 设置加载状态
})
.addCase(fetchConversationDetail.fulfilled, (state, action) => {
+ // 如果有返回数据
if (action.payload) {
- state.currentChat.status = 'succeeded';
- state.currentChat.data = action.payload;
- } else {
- state.currentChat.status = 'idle';
- state.currentChat.data = null;
+ const conversationId = action.payload.conversation_id;
+ const chatIndex = findChatIndex(state, conversationId);
+
+ if (chatIndex !== -1) {
+ // 更新现有聊天
+ state.chats.items[chatIndex] = {
+ ...state.chats.items[chatIndex],
+ ...action.payload,
+ };
+ } else {
+ // 添加新聊天
+ state.chats.items.push(action.payload);
+ }
+
+ // 设置为当前活跃聊天
+ state.activeConversationId = conversationId;
}
})
.addCase(fetchConversationDetail.rejected, (state, action) => {
- state.currentChat.status = 'failed';
- state.currentChat.error = action.payload || action.error.message;
+ // 仅在操作失败时设置错误状态
});
},
});
// 导出 actions
-export const {
- resetOperationStatus,
- resetCurrentChat,
- setCurrentChat,
- resetMessages,
- resetSendMessageStatus,
- addMessage,
- updateMessage,
-} = chatSlice.actions;
+export const { resetChatOperation, setActiveChat, resetMessageOperation, addMessage, updateMessage } =
+ chatSlice.actions;
// 导出 reducer
export default chatSlice.reducer;
diff --git a/src/store/chat/chat.thunks.js b/src/store/chat/chat.thunks.js
index 607c120..fe42f0c 100644
--- a/src/store/chat/chat.thunks.js
+++ b/src/store/chat/chat.thunks.js
@@ -1,7 +1,7 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import { get, post, put, del, streamRequest } from '../../services/api';
import { showNotification } from '../notification.slice';
-import { addMessage, updateMessage, setCurrentChat } from './chat.slice';
+import { addMessage, updateMessage, setActiveChat } from './chat.slice';
/**
* 获取聊天列表
@@ -30,29 +30,9 @@ export const fetchChats = createAsyncThunk('chat/fetchChats', async (params = {}
}
});
-/**
- * 创建新聊天
- * @param {Object} chatData - 聊天数据
- * @param {string} chatData.knowledge_base_id - 知识库ID
- * @param {string} chatData.title - 聊天标题
- */
-export const createChat = createAsyncThunk('chat/createChat', async (chatData, { rejectWithValue }) => {
- try {
- const response = await post('/chat-history/', chatData);
-
- // 处理返回格式
- if (response && response.code === 200) {
- return response.data.chat;
- }
-
- return response.data?.chat || {};
- } catch (error) {
- return rejectWithValue(error.response?.data?.message || 'Failed to create chat');
- }
-});
-
/**
* 更新聊天
+ * 更新已经发送出去的聊天,获得新的回复,相当于编辑以往的聊天记录。暂时未使用
* @param {Object} params - 更新参数
* @param {string} params.id - 聊天ID
* @param {Object} params.data - 更新数据
@@ -114,7 +94,8 @@ export const fetchAvailableDatasets = createAsyncThunk(
);
/**
- * 创建聊天记录
+ * 创建/继续聊天
+ * 创建新会话,或者继续一个已有的会话,根据conversation_id来更新
* @param {Object} params - 聊天参数
* @param {string[]} params.dataset_id_list - 知识库ID列表
* @param {string} params.question - 用户问题
@@ -134,24 +115,36 @@ export const createChatRecord = createAsyncThunk(
// 先添加用户消息到聊天窗口
const userMessageId = Date.now().toString();
+ const userMessage = {
+ id: userMessageId,
+ role: 'user',
+ content: question,
+ created_at: new Date().toISOString(),
+ };
+
+ // 添加用户消息
dispatch(
addMessage({
- id: userMessageId,
- role: 'user',
- content: question,
- created_at: new Date().toISOString(),
+ conversationId: conversation_id,
+ message: userMessage,
})
);
// 添加临时的助手消息(流式传输期间显示)
const assistantMessageId = (Date.now() + 1).toString();
+ const assistantMessage = {
+ id: assistantMessageId,
+ role: 'assistant',
+ content: '',
+ created_at: new Date().toISOString(),
+ is_streaming: true,
+ };
+
+ // 添加助手消息
dispatch(
addMessage({
- id: assistantMessageId,
- role: 'assistant',
- content: '',
- created_at: new Date().toISOString(),
- is_streaming: true,
+ conversationId: conversation_id,
+ message: assistantMessage,
})
);
@@ -185,11 +178,16 @@ export const createChatRecord = createAsyncThunk(
finalMessage += data.data.content;
console.log('累加内容:', finalMessage);
+ // 获取服务器消息ID (如果存在)
+ const serverMessageId = data.data.id;
+
// 更新消息内容
dispatch(
updateMessage({
- id: assistantMessageId,
- content: finalMessage,
+ conversationId: conversationId,
+ messageId: assistantMessageId,
+ serverMessageId: serverMessageId,
+ updates: { content: finalMessage },
})
);
}
@@ -197,10 +195,16 @@ export const createChatRecord = createAsyncThunk(
// 处理结束标志
if (data.data.is_end) {
console.log('检测到消息结束标志');
+
+ // 获取服务器消息ID (如果存在)
+ const serverMessageId = data.data.id;
+
dispatch(
updateMessage({
- id: assistantMessageId,
- is_streaming: false,
+ conversationId: conversationId,
+ messageId: assistantMessageId,
+ serverMessageId: serverMessageId,
+ updates: { is_streaming: false },
})
);
}
@@ -217,10 +221,15 @@ export const createChatRecord = createAsyncThunk(
messageType === '结束流式传输'
) {
console.log('收到完成消息');
+ // 获取服务器消息ID (如果存在)
+ const serverMessageId = data.data?.id;
+
dispatch(
updateMessage({
- id: assistantMessageId,
- is_streaming: false,
+ conversationId: conversationId,
+ messageId: assistantMessageId,
+ serverMessageId: serverMessageId,
+ updates: { is_streaming: false },
})
);
}
@@ -230,10 +239,15 @@ export const createChatRecord = createAsyncThunk(
// 如果有content字段,也尝试更新
if (data.data && data.data.content !== undefined) {
finalMessage += data.data.content;
+ // 获取服务器消息ID (如果存在)
+ const serverMessageId = data.data.id;
+
dispatch(
updateMessage({
- id: assistantMessageId,
- content: finalMessage,
+ conversationId: conversationId,
+ messageId: assistantMessageId,
+ serverMessageId: serverMessageId,
+ updates: { content: finalMessage },
})
);
}
@@ -250,9 +264,12 @@ export const createChatRecord = createAsyncThunk(
console.error('流式请求错误:', error);
dispatch(
updateMessage({
- id: assistantMessageId,
- content: `错误: ${error.message || '请求失败'}`,
- is_streaming: false,
+ conversationId: conversationId,
+ messageId: assistantMessageId,
+ updates: {
+ content: `错误: ${error.message || '请求失败'}`,
+ is_streaming: false,
+ },
})
);
}
@@ -261,8 +278,9 @@ export const createChatRecord = createAsyncThunk(
// 确保流式传输结束后标记消息已完成
dispatch(
updateMessage({
- id: assistantMessageId,
- is_streaming: false,
+ conversationId: conversationId,
+ messageId: assistantMessageId,
+ updates: { is_streaming: false },
})
);
@@ -277,7 +295,7 @@ export const createChatRecord = createAsyncThunk(
// 获取知识库信息
const state = getState();
const availableDatasets = state.chat.availableDatasets.items || [];
- const existingChats = state.chat.history.items || [];
+ const existingChats = state.chat.chats.items || [];
// 检查是否已存在此会话ID的记录
const existingChat = existingChats.find((chat) => chat.conversation_id === chatInfo.conversation_id);
@@ -303,6 +321,7 @@ export const createChatRecord = createAsyncThunk(
create_time: new Date().toISOString(),
last_message: question,
message_count: 2, // 用户问题和助手回复
+ messages: [userMessage, assistantMessage], // 添加消息到聊天记录
};
// 更新当前聊天
@@ -319,23 +338,7 @@ export const createChatRecord = createAsyncThunk(
}
// 设置为当前聊天
- dispatch(
- setCurrentChat({
- conversation_id: chatInfo.conversation_id,
- datasets: existingChat
- ? existingChat.datasets
- : dataset_id_list.map((id) => {
- const formattedId = id.includes('-')
- ? id
- : id.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5');
- const dataset = availableDatasets.find((ds) => ds.id === formattedId);
- return {
- id: formattedId,
- name: dataset?.name || '新知识库对话',
- };
- }),
- })
- );
+ dispatch(setActiveChat(chatInfo.conversation_id));
}
return chatInfo;
@@ -363,34 +366,11 @@ export const fetchConversationDetail = createAsyncThunk(
'chat/fetchConversationDetail',
async (conversationId, { rejectWithValue, dispatch, getState }) => {
try {
- // 先检查是否是刚创建的会话
- const state = getState();
- const createSession = state.chat.createSession || {};
- const currentChat = state.chat.currentChat.data;
-
- // 如果是刚创建成功的会话,且会话ID匹配,则直接返回现有会话数据
- if (
- createSession.status === 'succeeded' &&
- createSession.sessionId === conversationId &&
- currentChat?.conversation_id === conversationId
- ) {
- console.log('使用新创建的会话数据,跳过详情请求:', conversationId);
- return currentChat;
- }
-
const response = await get('/chat-history/conversation_detail', {
params: { conversation_id: conversationId },
});
if (response && response.code === 200) {
- // 如果存在消息,更新Redux状态
- if (response.data.messages) {
- dispatch({
- type: 'chat/fetchMessages/fulfilled',
- payload: response.data.messages,
- });
- }
-
return response.data;
}
@@ -411,7 +391,7 @@ export const fetchConversationDetail = createAsyncThunk(
);
/**
- * 创建新会话(仅获取会话ID,不发送消息)
+ * 创建新会话(仅获取会话ID,相当于一个会话凭证,不发送消息)
* @param {Object} params - 参数
* @param {string[]} params.dataset_id_list - 知识库ID列表
*/
@@ -450,6 +430,7 @@ export const createConversation = createAsyncThunk(
create_time: new Date().toISOString(),
last_message: '',
message_count: 0,
+ messages: [], // 初始化空消息数组
};
// 更新聊天历史列表
@@ -463,12 +444,7 @@ export const createConversation = createAsyncThunk(
});
// 设置为当前聊天
- dispatch(
- setCurrentChat({
- conversation_id: conversationData.conversation_id,
- datasets: newChatEntry.datasets,
- })
- );
+ dispatch(setActiveChat(conversationData.conversation_id));
return conversationData;
}
diff --git a/src/store/talentChat/talentChat.slice.js b/src/store/talentChat/talentChat.slice.js
index f1825ec..51ed15b 100644
--- a/src/store/talentChat/talentChat.slice.js
+++ b/src/store/talentChat/talentChat.slice.js
@@ -1,84 +1,84 @@
import { createSlice } from '@reduxjs/toolkit';
import { setUserGoal, getConversationSummary, getRecommendedReply } from './talentChat.thunks';
+// 初始状态
const initialState = {
- goal: {
+ userGoal: {
+ data: null,
status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
- error: null,
- data: {
- id: null,
- content: null,
- created_at: null,
- updated_at: null,
- },
+ error: null
},
- summary: {
+ conversationSummary: {
+ data: null,
status: 'idle',
- error: null,
- data: {
- id: null,
- talent_email: null,
- conversation_id: null,
- summary: null,
- created_at: null,
- updated_at: null,
- },
+ error: null
},
recommendedReply: {
+ data: null,
status: 'idle',
- error: null,
- reply: null,
- },
+ error: null
+ }
};
+// 创建 slice
const talentChatSlice = createSlice({
name: 'talentChat',
initialState,
- reducers: {},
+ reducers: {
+ resetTalentChat: (state) => {
+ state.userGoal = { data: null, status: 'idle', error: null };
+ state.conversationSummary = { data: null, status: 'idle', error: null };
+ state.recommendedReply = { data: null, status: 'idle', error: null };
+ }
+ },
extraReducers: (builder) => {
+ // 设置用户目标
builder
- // Handle setUserGoal
.addCase(setUserGoal.pending, (state) => {
- state.goal.status = 'loading';
+ state.userGoal.status = 'loading';
+ state.userGoal.error = null;
})
.addCase(setUserGoal.fulfilled, (state, action) => {
- state.goal.status = 'succeeded';
- state.goal.data = action.payload.goal;
- state.goal.error = null;
+ state.userGoal.status = 'succeeded';
+ state.userGoal.data = action.payload?.data || action.payload;
+ state.userGoal.error = null;
})
.addCase(setUserGoal.rejected, (state, action) => {
- state.goal.status = 'failed';
- state.goal.error = action.error.message;
+ state.userGoal.status = 'failed';
+ state.userGoal.error = action.payload || action.error.message;
})
- // Handle getConversationSummary
+ // 获取会话摘要
.addCase(getConversationSummary.pending, (state) => {
- state.summary.status = 'loading';
+ state.conversationSummary.status = 'loading';
+ state.conversationSummary.error = null;
})
.addCase(getConversationSummary.fulfilled, (state, action) => {
- state.summary.status = 'succeeded';
- state.summary.data = action.payload.summary;
- state.summary.error = null;
+ state.conversationSummary.status = 'succeeded';
+ state.conversationSummary.data = action.payload || null;
+ state.conversationSummary.error = null;
})
.addCase(getConversationSummary.rejected, (state, action) => {
- state.summary.status = 'failed';
- state.summary.error = action.error.message;
+ state.conversationSummary.status = 'failed';
+ state.conversationSummary.error = action.payload || action.error.message;
})
- // Handle getRecommendedReply
+ // 获取推荐回复
.addCase(getRecommendedReply.pending, (state) => {
state.recommendedReply.status = 'loading';
+ state.recommendedReply.error = null;
})
.addCase(getRecommendedReply.fulfilled, (state, action) => {
state.recommendedReply.status = 'succeeded';
- state.recommendedReply.reply = action.payload.reply;
+ state.recommendedReply.data = action.payload?.data || action.payload;
state.recommendedReply.error = null;
})
.addCase(getRecommendedReply.rejected, (state, action) => {
state.recommendedReply.status = 'failed';
- state.recommendedReply.error = action.error.message;
+ state.recommendedReply.error = action.payload || action.error.message;
});
- },
+ }
});
+export const { resetTalentChat } = talentChatSlice.actions;
export default talentChatSlice.reducer;
diff --git a/src/store/talentChat/talentChat.thunks.js b/src/store/talentChat/talentChat.thunks.js
index a3d4d90..3958465 100644
--- a/src/store/talentChat/talentChat.thunks.js
+++ b/src/store/talentChat/talentChat.thunks.js
@@ -23,8 +23,8 @@ export const getConversationSummary = createAsyncThunk(
talent_email: talentEmail,
};
- const response = await get('/conversation-summary/', { params });
- return response;
+ const { summary } = await get('/conversation-summary/', { params });
+ return summary;
} catch (error) {
return rejectWithValue(
error.response?.data?.message || error.message || 'Failed to get conversation summary'