Skip to content

Commit

Permalink
♻️ refactor: refactor the aiChat slice actions (#4542)
Browse files Browse the repository at this point in the history
* ✅ test: add test for files prompts

* ♻️ refactor: refactor the aiChat store
  • Loading branch information
arvinxx authored Oct 29, 2024
1 parent 2543f7e commit 8b33ba4
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/features/ChatInput/useSend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { useCallback, useMemo } from 'react';

import { useChatStore } from '@/store/chat';
import { chatSelectors } from '@/store/chat/selectors';
import { SendMessageParams } from '@/store/chat/slices/aiChat/action';
import { fileChatSelectors, useFileStore } from '@/store/file';
import { SendMessageParams } from '@/types/message';

export type UseSendMessageParams = Pick<
SendMessageParams,
Expand Down
117 changes: 117 additions & 0 deletions src/prompts/files/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { describe, expect, it } from 'vitest';

import { ChatFileItem, ChatImageItem } from '@/types/message';

import { filesPrompts } from './index';

describe('filesPrompts', () => {
// 创建测试用的示例数据
const mockImage: ChatImageItem = {
id: 'img-1',
alt: 'test image',
url: 'https://example.com/image.jpg',
};

const mockFile: ChatFileItem = {
id: 'file-1',
name: 'test.pdf',
fileType: 'application/pdf',
size: 1024,
url: 'https://example.com/test.pdf',
};

it('should generate prompt with only images', () => {
const result = filesPrompts({
imageList: [mockImage],
fileList: undefined,
});

expect(result).toEqual(
`<files_info>
<images>
<images_docstring>here are user upload images you can refer to</images_docstring>
<image name="test image" url="https://example.com/image.jpg"></image>
</images>
</files_info>`,
);
});

it('should generate prompt with only files', () => {
const result = filesPrompts({
imageList: [],
fileList: [mockFile],
});

expect(result).toEqual(
`<files_info>
<files>
<files_docstring>here are user upload files you can refer to</files_docstring>
<file id="file-1" name="test.pdf" type="application/pdf" size="1024" url="https://example.com/test.pdf"></file>
</files>
</files_info>`,
);
});

it('should generate prompt with both images and files', () => {
const result = filesPrompts({
imageList: [mockImage],
fileList: [mockFile],
});

expect(result).toEqual(
`<files_info>
<images>
<images_docstring>here are user upload images you can refer to</images_docstring>
<image name="test image" url="https://example.com/image.jpg"></image>
</images>
<files>
<files_docstring>here are user upload files you can refer to</files_docstring>
<file id="file-1" name="test.pdf" type="application/pdf" size="1024" url="https://example.com/test.pdf"></file>
</files>
</files_info>`,
);
});

it('should generate prompt with empty lists', () => {
const result = filesPrompts({
imageList: [],
fileList: [],
});

expect(result).toEqual('');
});

it('should handle multiple images and files', () => {
const images: ChatImageItem[] = [
mockImage,
{
id: 'img-2',
alt: 'second image',
url: 'https://example.com/image2.jpg',
},
];

const files: ChatFileItem[] = [
mockFile,
{
id: 'file-2',
name: 'document.docx',
fileType: 'application/docx',
size: 2048,
url: 'https://example.com/document.docx',
},
];

const result = filesPrompts({
imageList: images,
fileList: files,
});

expect(result).toContain('second image');
expect(result).toContain('document.docx');
expect(result).toMatch(/<image.*?>.*<image.*?>/s); // Check for multiple image tags
expect(result).toMatch(/<file.*?>.*<file.*?>/s); // Check for multiple file tags
});
});
2 changes: 2 additions & 0 deletions src/prompts/files/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export const filesPrompts = ({
fileList?: ChatFileItem[];
imageList: ChatImageItem[];
}) => {
if (imageList.length === 0 && (fileList || []).length === 0) return '';

const prompt = `<files_info>
${imagesPrompts(imageList)}
${fileList ? filePrompts(fileList) : ''}
Expand Down
2 changes: 1 addition & 1 deletion src/services/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ class ChatService {

const filesContext = filesPrompts({ fileList: m.fileList, imageList });
return [
{ text: m.content + '\n\n' + filesContext, type: 'text' },
{ text: (m.content + '\n\n' + filesContext).trim(), type: 'text' },
...imageList.map(
(i) => ({ image_url: { detail: 'auto', url: i.url }, type: 'image_url' }) as const,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { sessionMetaSelectors } from '@/store/session/selectors';
import { UploadFileItem } from '@/types/files/upload';
import { ChatMessage } from '@/types/message';

import { useChatStore } from '../../store';
import { useChatStore } from '../../../../store';

vi.stubGlobal(
'fetch',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,14 @@ import { chatHelpers } from '@/store/chat/helpers';
import { ChatStore } from '@/store/chat/store';
import { messageMapKey } from '@/store/chat/utils/messageMapKey';
import { useSessionStore } from '@/store/session';
import { UploadFileItem } from '@/types/files/upload';
import { ChatMessage, CreateMessageParams } from '@/types/message';
import { ChatMessage, CreateMessageParams, SendMessageParams } from '@/types/message';
import { MessageSemanticSearchChunk } from '@/types/rag';
import { setNamespace } from '@/utils/storeDebug';

import { chatSelectors, topicSelectors } from '../../selectors';
import { ChatRAGAction, chatRag } from './actions/rag';
import { chatSelectors, topicSelectors } from '../../../selectors';

const n = setNamespace('ai');

export interface SendMessageParams {
message: string;
files?: UploadFileItem[];
onlyAddUserMessage?: boolean;
/**
*
* https://github.com/lobehub/lobe-chat/pull/2086
*/
isWelcomeQuestion?: boolean;
}

interface ProcessMessageParams {
traceId?: string;
isWelcomeQuestion?: boolean;
Expand All @@ -46,7 +33,7 @@ interface ProcessMessageParams {
ragQuery?: string;
}

export interface ChatAIChatAction extends ChatRAGAction {
export interface AIGenerateAction {
/**
* Sends a new message to the AI chat system
*/
Expand Down Expand Up @@ -110,14 +97,12 @@ const getAgentConfig = () => agentSelectors.currentAgentConfig(useAgentStore.get
const getAgentChatConfig = () => agentSelectors.currentAgentChatConfig(useAgentStore.getState());
const getAgentKnowledge = () => agentSelectors.currentEnabledKnowledge(useAgentStore.getState());

export const chatAiChat: StateCreator<
export const generateAIChat: StateCreator<
ChatStore,
[['zustand/devtools', never]],
[],
ChatAIChatAction
> = (set, get, ...rest) => ({
...chatRag(set, get, ...rest),

AIGenerateAction
> = (set, get) => ({
delAndRegenerateMessage: async (id) => {
const traceId = chatSelectors.getTraceIdByMessageId(id)(get());
get().internal_resendMessage(id, traceId);
Expand Down
20 changes: 20 additions & 0 deletions src/store/chat/slices/aiChat/actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { StateCreator } from 'zustand/vanilla';

import { ChatStore } from '@/store/chat/store';

import { AIGenerateAction, generateAIChat } from './generateAIChat';
import { ChatRAGAction, chatRag } from './rag';

export interface ChatAIChatAction extends ChatRAGAction, AIGenerateAction {
/**/
}

export const chatAiChat: StateCreator<
ChatStore,
[['zustand/devtools', never]],
[],
ChatAIChatAction
> = (...params) => ({
...chatRag(...params),
...generateAIChat(...params),
});
2 changes: 1 addition & 1 deletion src/store/chat/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ChatMessageAction, chatMessage } from './slices/message/action';
import { ChatPluginAction, chatPlugin } from './slices/plugin/action';
import { ShareAction, chatShare } from './slices/share/action';
import { ChatTopicAction, chatTopic } from './slices/topic/action';
import { chatAiChat, ChatAIChatAction } from './slices/aiChat/action';
import { chatAiChat, ChatAIChatAction } from './slices/aiChat/actions';

export interface ChatStoreAction
extends ChatMessageAction,
Expand Down
12 changes: 12 additions & 0 deletions src/types/message/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { IPluginErrorType } from '@lobehub/chat-plugin-sdk';

import { ILobeAgentRuntimeErrorType } from '@/libs/agent-runtime';
import { ErrorType } from '@/types/fetch';
import { UploadFileItem } from '@/types/files';
import { MessageSemanticSearchChunk } from '@/types/rag';

import { BaseDataModel } from '../meta';
Expand Down Expand Up @@ -131,3 +132,14 @@ export interface CreateMessageParams
topicId?: string;
traceId?: string;
}

export interface SendMessageParams {
files?: UploadFileItem[];
/**
*
* https://github.com/lobehub/lobe-chat/pull/2086
*/
isWelcomeQuestion?: boolean;
message: string;
onlyAddUserMessage?: boolean;
}

0 comments on commit 8b33ba4

Please sign in to comment.