mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-15 04:00:09 +00:00
♻️ refactor: refactor services to a more clean structure (#10050)
* refactor services * clean tests * fix type
This commit is contained in:
@@ -51,3 +51,17 @@ export interface TopicRankItem {
|
||||
sessionId: string | null;
|
||||
title: string | null;
|
||||
}
|
||||
|
||||
export interface CreateTopicParams {
|
||||
favorite?: boolean;
|
||||
groupId?: string | null;
|
||||
messages?: string[];
|
||||
sessionId?: string | null;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface QueryTopicParams {
|
||||
containerId?: string | null; // sessionId or groupId
|
||||
current?: number;
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,13 @@ export const topicRouter = router({
|
||||
}),
|
||||
|
||||
searchTopics: topicProcedure
|
||||
.input(z.object({ keywords: z.string(), sessionId: z.string().nullable().optional() }))
|
||||
.input(
|
||||
z.object({
|
||||
groupId: z.string().nullable().optional(),
|
||||
keywords: z.string(),
|
||||
sessionId: z.string().nullable().optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
return ctx.topicModel.queryByKeyword(input.keywords, input.sessionId);
|
||||
}),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { testService } from '~test-utils';
|
||||
|
||||
import { ServerService } from './server';
|
||||
import { AiModelService } from './index';
|
||||
|
||||
describe('aiModelService', () => {
|
||||
testService(ServerService);
|
||||
describe('AiModelService', () => {
|
||||
testService(AiModelService);
|
||||
});
|
||||
|
||||
@@ -1,3 +1,57 @@
|
||||
import { ServerService } from './server';
|
||||
import {
|
||||
AiModelSortMap,
|
||||
AiProviderModelListItem,
|
||||
CreateAiModelParams,
|
||||
ToggleAiModelEnableParams,
|
||||
UpdateAiModelParams,
|
||||
} from 'model-bank';
|
||||
|
||||
export const aiModelService = new ServerService();
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
|
||||
export class AiModelService {
|
||||
createAiModel = async (params: CreateAiModelParams) => {
|
||||
return lambdaClient.aiModel.createAiModel.mutate(params);
|
||||
};
|
||||
|
||||
getAiProviderModelList = async (id: string): Promise<AiProviderModelListItem[]> => {
|
||||
return lambdaClient.aiModel.getAiProviderModelList.query({ id });
|
||||
};
|
||||
|
||||
getAiModelById = async (id: string) => {
|
||||
return lambdaClient.aiModel.getAiModelById.query({ id });
|
||||
};
|
||||
|
||||
toggleModelEnabled = async (params: ToggleAiModelEnableParams) => {
|
||||
return lambdaClient.aiModel.toggleModelEnabled.mutate(params);
|
||||
};
|
||||
|
||||
updateAiModel = async (id: string, providerId: string, value: UpdateAiModelParams) => {
|
||||
return lambdaClient.aiModel.updateAiModel.mutate({ id, providerId, value });
|
||||
};
|
||||
|
||||
batchUpdateAiModels = async (id: string, models: AiProviderModelListItem[]) => {
|
||||
return lambdaClient.aiModel.batchUpdateAiModels.mutate({ id, models });
|
||||
};
|
||||
|
||||
batchToggleAiModels = async (id: string, models: string[], enabled: boolean) => {
|
||||
return lambdaClient.aiModel.batchToggleAiModels.mutate({ enabled, id, models });
|
||||
};
|
||||
|
||||
clearModelsByProvider = async (providerId: string) => {
|
||||
return lambdaClient.aiModel.clearModelsByProvider.mutate({ providerId });
|
||||
};
|
||||
|
||||
clearRemoteModels = async (providerId: string) => {
|
||||
return lambdaClient.aiModel.clearRemoteModels.mutate({ providerId });
|
||||
};
|
||||
|
||||
updateAiModelOrder = async (providerId: string, items: AiModelSortMap[]) => {
|
||||
return lambdaClient.aiModel.updateAiModelOrder.mutate({ providerId, sortMap: items });
|
||||
};
|
||||
|
||||
deleteAiModel = async (params: { id: string; providerId: string }) => {
|
||||
return lambdaClient.aiModel.removeAiModel.mutate(params);
|
||||
};
|
||||
}
|
||||
|
||||
export const aiModelService = new AiModelService();
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
import { AiProviderModelListItem } from 'model-bank';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
|
||||
import { ServerService } from './server';
|
||||
|
||||
vi.mock('@/libs/trpc/client', () => ({
|
||||
lambdaClient: {
|
||||
aiModel: {
|
||||
createAiModel: { mutate: vi.fn() },
|
||||
getAiProviderModelList: { query: vi.fn() },
|
||||
getAiModelById: { query: vi.fn() },
|
||||
toggleModelEnabled: { mutate: vi.fn() },
|
||||
updateAiModel: { mutate: vi.fn() },
|
||||
batchUpdateAiModels: { mutate: vi.fn() },
|
||||
batchToggleAiModels: { mutate: vi.fn() },
|
||||
clearModelsByProvider: { mutate: vi.fn() },
|
||||
clearRemoteModels: { mutate: vi.fn() },
|
||||
updateAiModelOrder: { mutate: vi.fn() },
|
||||
removeAiModel: { mutate: vi.fn() },
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe('ServerService', () => {
|
||||
const service = new ServerService();
|
||||
|
||||
it('should create AI model', async () => {
|
||||
const params = {
|
||||
id: 'test-id',
|
||||
providerId: 'test-provider',
|
||||
displayName: 'Test Model',
|
||||
};
|
||||
await service.createAiModel(params);
|
||||
expect(vi.mocked(lambdaClient.aiModel.createAiModel.mutate)).toHaveBeenCalledWith(params);
|
||||
});
|
||||
|
||||
it('should get AI provider model list', async () => {
|
||||
await service.getAiProviderModelList('123');
|
||||
expect(vi.mocked(lambdaClient.aiModel.getAiProviderModelList.query)).toHaveBeenCalledWith({
|
||||
id: '123',
|
||||
});
|
||||
});
|
||||
|
||||
it('should get AI model by id', async () => {
|
||||
await service.getAiModelById('123');
|
||||
expect(vi.mocked(lambdaClient.aiModel.getAiModelById.query)).toHaveBeenCalledWith({
|
||||
id: '123',
|
||||
});
|
||||
});
|
||||
|
||||
it('should toggle model enabled', async () => {
|
||||
const params = { id: '123', providerId: 'test', enabled: true };
|
||||
await service.toggleModelEnabled(params);
|
||||
expect(vi.mocked(lambdaClient.aiModel.toggleModelEnabled.mutate)).toHaveBeenCalledWith(params);
|
||||
});
|
||||
|
||||
it('should update AI model', async () => {
|
||||
const value = { contextWindowTokens: 4000, displayName: 'Updated Model' };
|
||||
await service.updateAiModel('123', 'openai', value);
|
||||
expect(vi.mocked(lambdaClient.aiModel.updateAiModel.mutate)).toHaveBeenCalledWith({
|
||||
id: '123',
|
||||
providerId: 'openai',
|
||||
value,
|
||||
});
|
||||
});
|
||||
|
||||
it('should batch update AI models', async () => {
|
||||
const models: AiProviderModelListItem[] = [
|
||||
{
|
||||
id: '123',
|
||||
enabled: true,
|
||||
type: 'chat',
|
||||
},
|
||||
];
|
||||
await service.batchUpdateAiModels('provider1', models);
|
||||
expect(vi.mocked(lambdaClient.aiModel.batchUpdateAiModels.mutate)).toHaveBeenCalledWith({
|
||||
id: 'provider1',
|
||||
models,
|
||||
});
|
||||
});
|
||||
|
||||
it('should batch toggle AI models', async () => {
|
||||
const models = ['123', '456'];
|
||||
await service.batchToggleAiModels('provider1', models, true);
|
||||
expect(vi.mocked(lambdaClient.aiModel.batchToggleAiModels.mutate)).toHaveBeenCalledWith({
|
||||
id: 'provider1',
|
||||
models,
|
||||
enabled: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should clear models by provider', async () => {
|
||||
await service.clearModelsByProvider('provider1');
|
||||
expect(vi.mocked(lambdaClient.aiModel.clearModelsByProvider.mutate)).toHaveBeenCalledWith({
|
||||
providerId: 'provider1',
|
||||
});
|
||||
});
|
||||
|
||||
it('should clear remote models', async () => {
|
||||
await service.clearRemoteModels('provider1');
|
||||
expect(vi.mocked(lambdaClient.aiModel.clearRemoteModels.mutate)).toHaveBeenCalledWith({
|
||||
providerId: 'provider1',
|
||||
});
|
||||
});
|
||||
|
||||
it('should update AI model order', async () => {
|
||||
const items = [{ id: '123', sort: 1 }];
|
||||
await service.updateAiModelOrder('provider1', items);
|
||||
expect(vi.mocked(lambdaClient.aiModel.updateAiModelOrder.mutate)).toHaveBeenCalledWith({
|
||||
providerId: 'provider1',
|
||||
sortMap: items,
|
||||
});
|
||||
});
|
||||
|
||||
it('should delete AI model', async () => {
|
||||
const params = { id: '123', providerId: 'openai' };
|
||||
await service.deleteAiModel(params);
|
||||
expect(vi.mocked(lambdaClient.aiModel.removeAiModel.mutate)).toHaveBeenCalledWith(params);
|
||||
});
|
||||
});
|
||||
@@ -1,51 +0,0 @@
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { IAiModelService } from '@/services/aiModel/type';
|
||||
|
||||
export class ServerService implements IAiModelService {
|
||||
createAiModel: IAiModelService['createAiModel'] = async (params) => {
|
||||
return lambdaClient.aiModel.createAiModel.mutate(params);
|
||||
};
|
||||
|
||||
getAiProviderModelList: IAiModelService['getAiProviderModelList'] = async (id) => {
|
||||
return lambdaClient.aiModel.getAiProviderModelList.query({ id });
|
||||
};
|
||||
|
||||
getAiModelById: IAiModelService['getAiModelById'] = async (id) => {
|
||||
return lambdaClient.aiModel.getAiModelById.query({ id });
|
||||
};
|
||||
|
||||
toggleModelEnabled: IAiModelService['toggleModelEnabled'] = async (params) => {
|
||||
return lambdaClient.aiModel.toggleModelEnabled.mutate(params);
|
||||
};
|
||||
|
||||
updateAiModel: IAiModelService['updateAiModel'] = async (id, providerId, value) => {
|
||||
return lambdaClient.aiModel.updateAiModel.mutate({ id, providerId, value });
|
||||
};
|
||||
|
||||
batchUpdateAiModels: IAiModelService['batchUpdateAiModels'] = async (id, models) => {
|
||||
return lambdaClient.aiModel.batchUpdateAiModels.mutate({ id, models });
|
||||
};
|
||||
|
||||
batchToggleAiModels: IAiModelService['batchToggleAiModels'] = async (id, models, enabled) => {
|
||||
return lambdaClient.aiModel.batchToggleAiModels.mutate({ enabled, id, models });
|
||||
};
|
||||
|
||||
clearModelsByProvider: IAiModelService['clearModelsByProvider'] = async (providerId) => {
|
||||
return lambdaClient.aiModel.clearModelsByProvider.mutate({ providerId });
|
||||
};
|
||||
|
||||
clearRemoteModels: IAiModelService['clearRemoteModels'] = async (providerId) => {
|
||||
return lambdaClient.aiModel.clearRemoteModels.mutate({ providerId });
|
||||
};
|
||||
|
||||
updateAiModelOrder: IAiModelService['updateAiModelOrder'] = async (providerId, items) => {
|
||||
return lambdaClient.aiModel.updateAiModelOrder.mutate({ providerId, sortMap: items });
|
||||
};
|
||||
|
||||
deleteAiModel: IAiModelService['deleteAiModel'] = async (params: {
|
||||
id: string;
|
||||
providerId: string;
|
||||
}) => {
|
||||
return lambdaClient.aiModel.removeAiModel.mutate(params);
|
||||
};
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/* eslint-disable typescript-sort-keys/interface */
|
||||
import {
|
||||
AiModelSortMap,
|
||||
AiProviderModelListItem,
|
||||
CreateAiModelParams,
|
||||
ToggleAiModelEnableParams,
|
||||
UpdateAiModelParams,
|
||||
} from 'model-bank';
|
||||
|
||||
export interface IAiModelService {
|
||||
createAiModel: (params: CreateAiModelParams) => Promise<any>;
|
||||
|
||||
getAiProviderModelList: (id: string) => Promise<AiProviderModelListItem[]>;
|
||||
|
||||
getAiModelById: (id: string) => Promise<any>;
|
||||
|
||||
toggleModelEnabled: (params: ToggleAiModelEnableParams) => Promise<any>;
|
||||
|
||||
updateAiModel: (id: string, providerId: string, value: UpdateAiModelParams) => Promise<any>;
|
||||
|
||||
batchUpdateAiModels: (id: string, models: AiProviderModelListItem[]) => Promise<any>;
|
||||
|
||||
batchToggleAiModels: (id: string, models: string[], enabled: boolean) => Promise<any>;
|
||||
|
||||
clearRemoteModels: (providerId: string) => Promise<any>;
|
||||
|
||||
clearModelsByProvider: (providerId: string) => Promise<any>;
|
||||
|
||||
updateAiModelOrder: (providerId: string, items: AiModelSortMap[]) => Promise<any>;
|
||||
|
||||
deleteAiModel: (params: { id: string; providerId: string }) => Promise<any>;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { testService } from '~test-utils';
|
||||
|
||||
import { ServerService } from './server';
|
||||
import { AiProviderService } from './index';
|
||||
|
||||
describe('aiProviderService', () => {
|
||||
testService(ServerService);
|
||||
testService(AiProviderService);
|
||||
});
|
||||
|
||||
@@ -1,3 +1,49 @@
|
||||
import { ServerService } from './server';
|
||||
import {
|
||||
AiProviderDetailItem,
|
||||
AiProviderRuntimeState,
|
||||
AiProviderSortMap,
|
||||
CreateAiProviderParams,
|
||||
UpdateAiProviderConfigParams,
|
||||
} from '@/types/aiProvider';
|
||||
|
||||
export const aiProviderService = new ServerService();
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
|
||||
export class AiProviderService {
|
||||
createAiProvider = async (params: CreateAiProviderParams) => {
|
||||
return lambdaClient.aiProvider.createAiProvider.mutate(params);
|
||||
};
|
||||
|
||||
getAiProviderList = async () => {
|
||||
return lambdaClient.aiProvider.getAiProviderList.query();
|
||||
};
|
||||
|
||||
getAiProviderById = async (id: string): Promise<AiProviderDetailItem | undefined> => {
|
||||
return lambdaClient.aiProvider.getAiProviderById.query({ id });
|
||||
};
|
||||
|
||||
toggleProviderEnabled = async (id: string, enabled: boolean) => {
|
||||
return lambdaClient.aiProvider.toggleProviderEnabled.mutate({ enabled, id });
|
||||
};
|
||||
|
||||
updateAiProvider = async (id: string, value: any) => {
|
||||
return lambdaClient.aiProvider.updateAiProvider.mutate({ id, value });
|
||||
};
|
||||
|
||||
updateAiProviderConfig = async (id: string, value: UpdateAiProviderConfigParams) => {
|
||||
return lambdaClient.aiProvider.updateAiProviderConfig.mutate({ id, value });
|
||||
};
|
||||
|
||||
updateAiProviderOrder = async (items: AiProviderSortMap[]) => {
|
||||
return lambdaClient.aiProvider.updateAiProviderOrder.mutate({ sortMap: items });
|
||||
};
|
||||
|
||||
deleteAiProvider = async (id: string) => {
|
||||
return lambdaClient.aiProvider.removeAiProvider.mutate({ id });
|
||||
};
|
||||
|
||||
getAiProviderRuntimeState = async (isLogin?: boolean): Promise<AiProviderRuntimeState> => {
|
||||
return lambdaClient.aiProvider.getAiProviderRuntimeState.query({ isLogin });
|
||||
};
|
||||
}
|
||||
|
||||
export const aiProviderService = new AiProviderService();
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
|
||||
import { IAiProviderService } from './type';
|
||||
|
||||
export class ServerService implements IAiProviderService {
|
||||
createAiProvider: IAiProviderService['createAiProvider'] = async (params) => {
|
||||
return lambdaClient.aiProvider.createAiProvider.mutate(params);
|
||||
};
|
||||
|
||||
getAiProviderList: IAiProviderService['getAiProviderList'] = async () => {
|
||||
return lambdaClient.aiProvider.getAiProviderList.query();
|
||||
};
|
||||
|
||||
getAiProviderById: IAiProviderService['getAiProviderById'] = async (id) => {
|
||||
return lambdaClient.aiProvider.getAiProviderById.query({ id });
|
||||
};
|
||||
|
||||
toggleProviderEnabled: IAiProviderService['toggleProviderEnabled'] = async (id, enabled) => {
|
||||
return lambdaClient.aiProvider.toggleProviderEnabled.mutate({ enabled, id });
|
||||
};
|
||||
|
||||
updateAiProvider: IAiProviderService['updateAiProvider'] = async (id, value) => {
|
||||
return lambdaClient.aiProvider.updateAiProvider.mutate({ id, value });
|
||||
};
|
||||
|
||||
updateAiProviderConfig: IAiProviderService['updateAiProviderConfig'] = async (id, value) => {
|
||||
return lambdaClient.aiProvider.updateAiProviderConfig.mutate({ id, value });
|
||||
};
|
||||
|
||||
updateAiProviderOrder: IAiProviderService['updateAiProviderOrder'] = async (items) => {
|
||||
return lambdaClient.aiProvider.updateAiProviderOrder.mutate({ sortMap: items });
|
||||
};
|
||||
|
||||
deleteAiProvider: IAiProviderService['deleteAiProvider'] = async (id) => {
|
||||
return lambdaClient.aiProvider.removeAiProvider.mutate({ id });
|
||||
};
|
||||
|
||||
getAiProviderRuntimeState: IAiProviderService['getAiProviderRuntimeState'] = async (
|
||||
isLogin?: boolean,
|
||||
) => {
|
||||
return lambdaClient.aiProvider.getAiProviderRuntimeState.query({ isLogin });
|
||||
};
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import {
|
||||
AiProviderDetailItem,
|
||||
AiProviderRuntimeState,
|
||||
AiProviderSortMap,
|
||||
CreateAiProviderParams,
|
||||
UpdateAiProviderConfigParams,
|
||||
} from '@/types/aiProvider';
|
||||
|
||||
export interface IAiProviderService {
|
||||
createAiProvider: (params: CreateAiProviderParams) => Promise<any>;
|
||||
|
||||
deleteAiProvider: (id: string) => Promise<any>;
|
||||
|
||||
getAiProviderById: (id: string) => Promise<AiProviderDetailItem | undefined>;
|
||||
|
||||
getAiProviderList: () => Promise<any>;
|
||||
|
||||
getAiProviderRuntimeState: (isLogin?: boolean) => Promise<AiProviderRuntimeState>;
|
||||
|
||||
toggleProviderEnabled: (id: string, enabled: boolean) => Promise<any>;
|
||||
|
||||
updateAiProvider: (id: string, value: any) => Promise<any>;
|
||||
|
||||
updateAiProviderConfig: (id: string, value: UpdateAiProviderConfigParams) => Promise<any>;
|
||||
|
||||
updateAiProviderOrder: (items: AiProviderSortMap[]) => Promise<any>;
|
||||
}
|
||||
@@ -1,3 +1,67 @@
|
||||
import { ServerService } from './server';
|
||||
import {
|
||||
ChatGroupAgentItem,
|
||||
ChatGroupItem,
|
||||
NewChatGroup,
|
||||
NewChatGroupAgent,
|
||||
} from '@/database/schemas';
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
|
||||
export const chatGroupService = new ServerService();
|
||||
class ChatGroupService {
|
||||
createGroup = (params: Omit<NewChatGroup, 'userId'>): Promise<ChatGroupItem> => {
|
||||
return lambdaClient.group.createGroup.mutate({
|
||||
...params,
|
||||
config: params.config as any,
|
||||
});
|
||||
};
|
||||
|
||||
updateGroup = (id: string, value: Partial<ChatGroupItem>): Promise<ChatGroupItem> => {
|
||||
return lambdaClient.group.updateGroup.mutate({
|
||||
id,
|
||||
value: {
|
||||
...value,
|
||||
config: value.config as any,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
deleteGroup = (id: string) => {
|
||||
return lambdaClient.group.deleteGroup.mutate({ id });
|
||||
};
|
||||
|
||||
getGroup = (id: string): Promise<ChatGroupItem | undefined> => {
|
||||
return lambdaClient.group.getGroup.query({ id });
|
||||
};
|
||||
|
||||
getGroups = (): Promise<ChatGroupItem[]> => {
|
||||
return lambdaClient.group.getGroups.query();
|
||||
};
|
||||
|
||||
addAgentsToGroup = (groupId: string, agentIds: string[]): Promise<ChatGroupAgentItem[]> => {
|
||||
return lambdaClient.group.addAgentsToGroup.mutate({ agentIds, groupId });
|
||||
};
|
||||
|
||||
removeAgentsFromGroup = (groupId: string, agentIds: string[]) => {
|
||||
return lambdaClient.group.removeAgentsFromGroup.mutate({ agentIds, groupId });
|
||||
};
|
||||
|
||||
updateAgentInGroup = (
|
||||
groupId: string,
|
||||
agentId: string,
|
||||
updates: Partial<Pick<NewChatGroupAgent, 'order' | 'role'>>,
|
||||
): Promise<ChatGroupAgentItem> => {
|
||||
return lambdaClient.group.updateAgentInGroup.mutate({
|
||||
agentId,
|
||||
groupId,
|
||||
updates: {
|
||||
order: updates.order === null ? undefined : updates.order,
|
||||
role: updates.role === null ? undefined : updates.role,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
getGroupAgents = (groupId: string): Promise<ChatGroupAgentItem[]> => {
|
||||
return lambdaClient.group.getGroupAgents.query({ groupId });
|
||||
};
|
||||
}
|
||||
|
||||
export const chatGroupService = new ChatGroupService();
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
import {
|
||||
ChatGroupAgentItem,
|
||||
ChatGroupItem,
|
||||
NewChatGroup,
|
||||
NewChatGroupAgent,
|
||||
} from '@/database/schemas';
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
|
||||
import { IChatGroupService } from './type';
|
||||
|
||||
export class ServerService implements IChatGroupService {
|
||||
createGroup(params: Omit<NewChatGroup, 'userId'>): Promise<ChatGroupItem> {
|
||||
return lambdaClient.group.createGroup.mutate({
|
||||
...params,
|
||||
config: params.config as any,
|
||||
});
|
||||
}
|
||||
|
||||
updateGroup(id: string, value: Partial<ChatGroupItem>): Promise<ChatGroupItem> {
|
||||
return lambdaClient.group.updateGroup.mutate({
|
||||
id,
|
||||
value: {
|
||||
...value,
|
||||
config: value.config as any,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
deleteGroup(id: string): Promise<any> {
|
||||
return lambdaClient.group.deleteGroup.mutate({ id });
|
||||
}
|
||||
|
||||
getGroup(id: string): Promise<ChatGroupItem | undefined> {
|
||||
return lambdaClient.group.getGroup.query({ id });
|
||||
}
|
||||
|
||||
getGroups(): Promise<ChatGroupItem[]> {
|
||||
return lambdaClient.group.getGroups.query();
|
||||
}
|
||||
|
||||
addAgentsToGroup(groupId: string, agentIds: string[]): Promise<ChatGroupAgentItem[]> {
|
||||
return lambdaClient.group.addAgentsToGroup.mutate({ agentIds, groupId });
|
||||
}
|
||||
|
||||
removeAgentsFromGroup(groupId: string, agentIds: string[]): Promise<any> {
|
||||
return lambdaClient.group.removeAgentsFromGroup.mutate({ agentIds, groupId });
|
||||
}
|
||||
|
||||
updateAgentInGroup(
|
||||
groupId: string,
|
||||
agentId: string,
|
||||
updates: Partial<Pick<NewChatGroupAgent, 'order' | 'role'>>,
|
||||
): Promise<ChatGroupAgentItem> {
|
||||
return lambdaClient.group.updateAgentInGroup.mutate({
|
||||
agentId,
|
||||
groupId,
|
||||
updates: {
|
||||
order: updates.order === null ? undefined : updates.order,
|
||||
role: updates.role === null ? undefined : updates.role,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getGroupAgents(groupId: string): Promise<ChatGroupAgentItem[]> {
|
||||
return lambdaClient.group.getGroupAgents.query({ groupId });
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import {
|
||||
ChatGroupAgentItem,
|
||||
ChatGroupItem,
|
||||
NewChatGroup,
|
||||
NewChatGroupAgent,
|
||||
} from '@/database/schemas';
|
||||
|
||||
export interface IChatGroupService {
|
||||
addAgentsToGroup(groupId: string, agentIds: string[]): Promise<ChatGroupAgentItem[]>;
|
||||
createGroup(params: Omit<NewChatGroup, 'userId'>): Promise<ChatGroupItem>;
|
||||
deleteGroup(id: string): Promise<any>;
|
||||
getGroup(id: string): Promise<ChatGroupItem | undefined>;
|
||||
getGroupAgents(groupId: string): Promise<ChatGroupAgentItem[]>;
|
||||
getGroups(): Promise<ChatGroupItem[]>;
|
||||
removeAgentsFromGroup(groupId: string, agentIds: string[]): Promise<any>;
|
||||
updateAgentInGroup(
|
||||
groupId: string,
|
||||
agentId: string,
|
||||
updates: Partial<Pick<NewChatGroupAgent, 'order' | 'role'>>,
|
||||
): Promise<ChatGroupAgentItem>;
|
||||
updateGroup(id: string, value: Partial<ChatGroupItem>): Promise<ChatGroupItem>;
|
||||
}
|
||||
@@ -1,3 +1,11 @@
|
||||
import { ServerService } from './server';
|
||||
import { ExportDatabaseData } from '@/types/export';
|
||||
|
||||
export const exportService = new ServerService();
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
|
||||
class ExportService {
|
||||
exportData = async (): Promise<ExportDatabaseData> => {
|
||||
return await lambdaClient.exporter.exportData.mutate();
|
||||
};
|
||||
}
|
||||
|
||||
export const exportService = new ExportService();
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
|
||||
import { IExportService } from './type';
|
||||
|
||||
export class ServerService implements IExportService {
|
||||
exportData: IExportService['exportData'] = async () => {
|
||||
return await lambdaClient.exporter.exportData.mutate();
|
||||
};
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { ExportDatabaseData } from '@/types/export';
|
||||
|
||||
export interface IExportService {
|
||||
exportData(): Promise<ExportDatabaseData>;
|
||||
}
|
||||
@@ -1,3 +1,62 @@
|
||||
import { ServerService } from './server';
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import {
|
||||
CheckFileHashResult,
|
||||
FileItem,
|
||||
QueryFileListParams,
|
||||
QueryFileListSchemaType,
|
||||
UploadFileParams,
|
||||
} from '@/types/files';
|
||||
|
||||
export const fileService = new ServerService();
|
||||
interface CreateFileParams extends Omit<UploadFileParams, 'url'> {
|
||||
knowledgeBaseId?: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export class FileService {
|
||||
createFile = async (
|
||||
params: UploadFileParams,
|
||||
knowledgeBaseId?: string,
|
||||
): Promise<{ id: string; url: string }> => {
|
||||
return lambdaClient.file.createFile.mutate({ ...params, knowledgeBaseId } as CreateFileParams);
|
||||
};
|
||||
|
||||
getFile = async (id: string): Promise<FileItem> => {
|
||||
const item = await lambdaClient.file.findById.query({ id });
|
||||
|
||||
if (!item) {
|
||||
throw new Error('file not found');
|
||||
}
|
||||
|
||||
return { ...item, type: item.fileType };
|
||||
};
|
||||
|
||||
removeFile = async (id: string): Promise<void> => {
|
||||
await lambdaClient.file.removeFile.mutate({ id });
|
||||
};
|
||||
|
||||
removeFiles = async (ids: string[]): Promise<void> => {
|
||||
await lambdaClient.file.removeFiles.mutate({ ids });
|
||||
};
|
||||
|
||||
removeAllFiles = async () => {
|
||||
await lambdaClient.file.removeAllFiles.mutate();
|
||||
};
|
||||
|
||||
getFiles = async (params: QueryFileListParams) => {
|
||||
return lambdaClient.file.getFiles.query(params as QueryFileListSchemaType);
|
||||
};
|
||||
|
||||
getFileItem = async (id: string) => {
|
||||
return lambdaClient.file.getFileItemById.query({ id });
|
||||
};
|
||||
|
||||
checkFileHash = async (hash: string): Promise<CheckFileHashResult> => {
|
||||
return lambdaClient.file.checkFileHash.mutate({ hash });
|
||||
};
|
||||
|
||||
removeFileAsyncTask = async (id: string, type: 'embedding' | 'chunk') => {
|
||||
return lambdaClient.file.removeFileAsyncTask.mutate({ id, type });
|
||||
};
|
||||
}
|
||||
|
||||
export const fileService = new FileService();
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { QueryFileListParams, QueryFileListSchemaType, UploadFileParams } from '@/types/files';
|
||||
|
||||
import { IFileService } from './type';
|
||||
|
||||
interface CreateFileParams extends Omit<UploadFileParams, 'url'> {
|
||||
knowledgeBaseId?: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export class ServerService implements IFileService {
|
||||
createFile: IFileService['createFile'] = async (params, knowledgeBaseId) => {
|
||||
return lambdaClient.file.createFile.mutate({ ...params, knowledgeBaseId } as CreateFileParams);
|
||||
};
|
||||
|
||||
getFile: IFileService['getFile'] = async (id) => {
|
||||
const item = await lambdaClient.file.findById.query({ id });
|
||||
|
||||
if (!item) {
|
||||
throw new Error('file not found');
|
||||
}
|
||||
|
||||
return { ...item, type: item.fileType };
|
||||
};
|
||||
|
||||
removeFile: IFileService['removeFile'] = async (id) => {
|
||||
await lambdaClient.file.removeFile.mutate({ id });
|
||||
};
|
||||
|
||||
removeFiles: IFileService['removeFiles'] = async (ids) => {
|
||||
await lambdaClient.file.removeFiles.mutate({ ids });
|
||||
};
|
||||
|
||||
removeAllFiles: IFileService['removeAllFiles'] = async () => {
|
||||
await lambdaClient.file.removeAllFiles.mutate();
|
||||
};
|
||||
|
||||
getFiles = async (params: QueryFileListParams) => {
|
||||
return lambdaClient.file.getFiles.query(params as QueryFileListSchemaType);
|
||||
};
|
||||
|
||||
getFileItem = async (id: string) => {
|
||||
return lambdaClient.file.getFileItemById.query({ id });
|
||||
};
|
||||
|
||||
checkFileHash: IFileService['checkFileHash'] = async (hash) => {
|
||||
return lambdaClient.file.checkFileHash.mutate({ hash });
|
||||
};
|
||||
|
||||
removeFileAsyncTask = async (id: string, type: 'embedding' | 'chunk') => {
|
||||
return lambdaClient.file.removeFileAsyncTask.mutate({ id, type });
|
||||
};
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import { CheckFileHashResult, FileItem, UploadFileParams } from '@/types/files';
|
||||
|
||||
export interface IFileService {
|
||||
checkFileHash(hash: string): Promise<CheckFileHashResult>;
|
||||
createFile(
|
||||
file: UploadFileParams,
|
||||
knowledgeBaseId?: string,
|
||||
): Promise<{ id: string; url: string }>;
|
||||
getFile(id: string): Promise<FileItem>;
|
||||
removeAllFiles(): Promise<any>;
|
||||
removeFile(id: string): Promise<void>;
|
||||
removeFiles(ids: string[]): Promise<void>;
|
||||
}
|
||||
@@ -1,3 +1,134 @@
|
||||
import { ServerService } from './server';
|
||||
import { DefaultErrorShape } from '@trpc/server/unstable-core-do-not-import';
|
||||
|
||||
export const importService = new ServerService();
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { uploadService } from '@/services/upload';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { ImportPgDataStructure } from '@/types/export';
|
||||
import { ImporterEntryData, ImportStage, OnImportCallbacks } from '@/types/importer';
|
||||
import { UserSettings } from '@/types/user/settings';
|
||||
import { uuid } from '@/utils/uuid';
|
||||
|
||||
class ImportService {
|
||||
importSettings = async (settings: UserSettings): Promise<void> => {
|
||||
await useUserStore.getState().importAppSettings(settings);
|
||||
};
|
||||
|
||||
importData = async (data: ImporterEntryData, callbacks?: OnImportCallbacks): Promise<void> => {
|
||||
const handleError = (e: unknown) => {
|
||||
callbacks?.onStageChange?.(ImportStage.Error);
|
||||
const error = e as DefaultErrorShape;
|
||||
|
||||
callbacks?.onError?.({
|
||||
code: error.data.code,
|
||||
httpStatus: error.data.httpStatus,
|
||||
message: error.message,
|
||||
path: error.data.path,
|
||||
});
|
||||
};
|
||||
|
||||
const totalLength =
|
||||
(data.messages?.length || 0) +
|
||||
(data.sessionGroups?.length || 0) +
|
||||
(data.sessions?.length || 0) +
|
||||
(data.topics?.length || 0);
|
||||
|
||||
if (totalLength < 500) {
|
||||
callbacks?.onStageChange?.(ImportStage.Importing);
|
||||
const time = Date.now();
|
||||
try {
|
||||
const result = await lambdaClient.importer.importByPost.mutate({ data });
|
||||
const duration = Date.now() - time;
|
||||
|
||||
callbacks?.onStageChange?.(ImportStage.Success);
|
||||
callbacks?.onSuccess?.(result.results, duration);
|
||||
} catch (e) {
|
||||
handleError(e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await this.uploadData(data, { callbacks, handleError });
|
||||
};
|
||||
|
||||
importPgData = async (
|
||||
data: ImportPgDataStructure,
|
||||
options?: {
|
||||
callbacks?: OnImportCallbacks;
|
||||
overwriteExisting?: boolean;
|
||||
},
|
||||
): Promise<void> => {
|
||||
const { callbacks } = options || {};
|
||||
|
||||
const handleError = (e: unknown) => {
|
||||
callbacks?.onStageChange?.(ImportStage.Error);
|
||||
const error = e as DefaultErrorShape;
|
||||
|
||||
callbacks?.onError?.({
|
||||
code: error.data.code,
|
||||
httpStatus: error.data.httpStatus,
|
||||
message: error.message,
|
||||
path: error.data.path,
|
||||
});
|
||||
};
|
||||
|
||||
const totalLength = Object.values(data.data)
|
||||
.map((d) => d.length)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
|
||||
if (totalLength < 500) {
|
||||
callbacks?.onStageChange?.(ImportStage.Importing);
|
||||
const time = Date.now();
|
||||
try {
|
||||
const result = await lambdaClient.importer.importPgByPost.mutate(data);
|
||||
const duration = Date.now() - time;
|
||||
|
||||
callbacks?.onStageChange?.(ImportStage.Success);
|
||||
callbacks?.onSuccess?.(result.results, duration);
|
||||
} catch (e) {
|
||||
handleError(e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await this.uploadData(data, { callbacks, handleError });
|
||||
};
|
||||
|
||||
private uploadData = async (
|
||||
data: object,
|
||||
{ callbacks, handleError }: { callbacks?: OnImportCallbacks; handleError: (e: unknown) => any },
|
||||
) => {
|
||||
// if the data is too large, upload it to S3 and upload by file
|
||||
const filename = `${uuid()}.json`;
|
||||
|
||||
let pathname;
|
||||
try {
|
||||
callbacks?.onStageChange?.(ImportStage.Uploading);
|
||||
const result = await uploadService.uploadDataToS3(data, {
|
||||
filename,
|
||||
onProgress: (status, state) => {
|
||||
callbacks?.onFileUploading?.(state);
|
||||
},
|
||||
pathname: `import_config/${filename}`,
|
||||
});
|
||||
pathname = result.data.path;
|
||||
console.log(pathname);
|
||||
} catch {
|
||||
throw new Error('Upload Error');
|
||||
}
|
||||
|
||||
callbacks?.onStageChange?.(ImportStage.Importing);
|
||||
const time = Date.now();
|
||||
try {
|
||||
const result = await lambdaClient.importer.importByFile.mutate({ pathname });
|
||||
const duration = Date.now() - time;
|
||||
callbacks?.onStageChange?.(ImportStage.Success);
|
||||
callbacks?.onSuccess?.(result.results, duration);
|
||||
} catch (e) {
|
||||
handleError(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const importService = new ImportService();
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
import { DefaultErrorShape } from '@trpc/server/unstable-core-do-not-import';
|
||||
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { uploadService } from '@/services/upload';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { ImportPgDataStructure } from '@/types/export';
|
||||
import { ImportStage, OnImportCallbacks } from '@/types/importer';
|
||||
import { uuid } from '@/utils/uuid';
|
||||
|
||||
import { IImportService } from './type';
|
||||
|
||||
export class ServerService implements IImportService {
|
||||
importSettings: IImportService['importSettings'] = async (settings) => {
|
||||
await useUserStore.getState().importAppSettings(settings);
|
||||
};
|
||||
|
||||
importData: IImportService['importData'] = async (data, callbacks) => {
|
||||
const handleError = (e: unknown) => {
|
||||
callbacks?.onStageChange?.(ImportStage.Error);
|
||||
const error = e as DefaultErrorShape;
|
||||
|
||||
callbacks?.onError?.({
|
||||
code: error.data.code,
|
||||
httpStatus: error.data.httpStatus,
|
||||
message: error.message,
|
||||
path: error.data.path,
|
||||
});
|
||||
};
|
||||
|
||||
const totalLength =
|
||||
(data.messages?.length || 0) +
|
||||
(data.sessionGroups?.length || 0) +
|
||||
(data.sessions?.length || 0) +
|
||||
(data.topics?.length || 0);
|
||||
|
||||
if (totalLength < 500) {
|
||||
callbacks?.onStageChange?.(ImportStage.Importing);
|
||||
const time = Date.now();
|
||||
try {
|
||||
const result = await lambdaClient.importer.importByPost.mutate({ data });
|
||||
const duration = Date.now() - time;
|
||||
|
||||
callbacks?.onStageChange?.(ImportStage.Success);
|
||||
callbacks?.onSuccess?.(result.results, duration);
|
||||
} catch (e) {
|
||||
handleError(e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await this.uploadData(data, { callbacks, handleError });
|
||||
};
|
||||
|
||||
importPgData: IImportService['importPgData'] = async (
|
||||
data: ImportPgDataStructure,
|
||||
{
|
||||
callbacks,
|
||||
}: {
|
||||
callbacks?: OnImportCallbacks;
|
||||
overwriteExisting?: boolean;
|
||||
} = {},
|
||||
): Promise<void> => {
|
||||
const handleError = (e: unknown) => {
|
||||
callbacks?.onStageChange?.(ImportStage.Error);
|
||||
const error = e as DefaultErrorShape;
|
||||
|
||||
callbacks?.onError?.({
|
||||
code: error.data.code,
|
||||
httpStatus: error.data.httpStatus,
|
||||
message: error.message,
|
||||
path: error.data.path,
|
||||
});
|
||||
};
|
||||
|
||||
const totalLength = Object.values(data.data)
|
||||
.map((d) => d.length)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
|
||||
if (totalLength < 500) {
|
||||
callbacks?.onStageChange?.(ImportStage.Importing);
|
||||
const time = Date.now();
|
||||
try {
|
||||
const result = await lambdaClient.importer.importPgByPost.mutate(data);
|
||||
const duration = Date.now() - time;
|
||||
|
||||
callbacks?.onStageChange?.(ImportStage.Success);
|
||||
callbacks?.onSuccess?.(result.results, duration);
|
||||
} catch (e) {
|
||||
handleError(e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await this.uploadData(data, { callbacks, handleError });
|
||||
};
|
||||
|
||||
private uploadData = async (
|
||||
data: object,
|
||||
{ callbacks, handleError }: { callbacks?: OnImportCallbacks; handleError: (e: unknown) => any },
|
||||
) => {
|
||||
// if the data is too large, upload it to S3 and upload by file
|
||||
const filename = `${uuid()}.json`;
|
||||
|
||||
let pathname;
|
||||
try {
|
||||
callbacks?.onStageChange?.(ImportStage.Uploading);
|
||||
const result = await uploadService.uploadDataToS3(data, {
|
||||
filename,
|
||||
onProgress: (status, state) => {
|
||||
callbacks?.onFileUploading?.(state);
|
||||
},
|
||||
pathname: `import_config/${filename}`,
|
||||
});
|
||||
pathname = result.data.path;
|
||||
console.log(pathname);
|
||||
} catch {
|
||||
throw new Error('Upload Error');
|
||||
}
|
||||
|
||||
callbacks?.onStageChange?.(ImportStage.Importing);
|
||||
const time = Date.now();
|
||||
try {
|
||||
const result = await lambdaClient.importer.importByFile.mutate({ pathname });
|
||||
const duration = Date.now() - time;
|
||||
callbacks?.onStageChange?.(ImportStage.Success);
|
||||
callbacks?.onSuccess?.(result.results, duration);
|
||||
} catch (e) {
|
||||
handleError(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { ImportPgDataStructure } from '@/types/export';
|
||||
import { ImporterEntryData, OnImportCallbacks } from '@/types/importer';
|
||||
import { UserSettings } from '@/types/user/settings';
|
||||
|
||||
export interface IImportService {
|
||||
importData(data: ImporterEntryData, callbacks?: OnImportCallbacks): Promise<void>;
|
||||
|
||||
importPgData(
|
||||
data: ImportPgDataStructure,
|
||||
options?: {
|
||||
callbacks?: OnImportCallbacks;
|
||||
overwriteExisting?: boolean;
|
||||
},
|
||||
): Promise<void>;
|
||||
|
||||
importSettings(settings: UserSettings): Promise<void>;
|
||||
}
|
||||
@@ -1,3 +1,177 @@
|
||||
import { ServerService } from './server';
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import {
|
||||
ChatMessageError,
|
||||
ChatMessagePluginError,
|
||||
ChatTranslate,
|
||||
ChatTTS,
|
||||
CreateMessageParams,
|
||||
CreateMessageResult,
|
||||
ModelRankItem,
|
||||
UIChatMessage,
|
||||
UpdateMessageParams,
|
||||
UpdateMessageRAGParams,
|
||||
UpdateMessageResult,
|
||||
} from '@lobechat/types';
|
||||
import type { HeatmapsProps } from '@lobehub/charts';
|
||||
|
||||
export const messageService = new ServerService();
|
||||
import { INBOX_SESSION_ID } from '@/const/session';
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { labPreferSelectors } from '@/store/user/selectors';
|
||||
|
||||
export class MessageService {
|
||||
createMessage = async ({ sessionId, ...params }: CreateMessageParams): Promise<string> => {
|
||||
return lambdaClient.message.createMessage.mutate({
|
||||
...params,
|
||||
sessionId: sessionId ? this.toDbSessionId(sessionId) : undefined,
|
||||
});
|
||||
};
|
||||
|
||||
createNewMessage = async ({
|
||||
sessionId,
|
||||
...params
|
||||
}: CreateMessageParams): Promise<CreateMessageResult> => {
|
||||
return lambdaClient.message.createNewMessage.mutate({
|
||||
...params,
|
||||
sessionId: sessionId ? this.toDbSessionId(sessionId) : undefined,
|
||||
});
|
||||
};
|
||||
|
||||
getMessages = async (
|
||||
sessionId: string,
|
||||
topicId?: string,
|
||||
groupId?: string,
|
||||
): Promise<UIChatMessage[]> => {
|
||||
// Get user lab preference for message grouping
|
||||
const useGroup = labPreferSelectors.enableAssistantMessageGroup(useUserStore.getState());
|
||||
|
||||
const data = await lambdaClient.message.getMessages.query({
|
||||
groupId,
|
||||
sessionId: this.toDbSessionId(sessionId),
|
||||
topicId,
|
||||
useGroup,
|
||||
});
|
||||
|
||||
return data as unknown as UIChatMessage[];
|
||||
};
|
||||
|
||||
getGroupMessages = async (groupId: string, topicId?: string): Promise<UIChatMessage[]> => {
|
||||
// Get user lab preference for message grouping
|
||||
const useGroup = labPreferSelectors.enableAssistantMessageGroup(useUserStore.getState());
|
||||
|
||||
const data = await lambdaClient.message.getMessages.query({
|
||||
groupId,
|
||||
topicId,
|
||||
useGroup,
|
||||
});
|
||||
return data as unknown as UIChatMessage[];
|
||||
};
|
||||
|
||||
countMessages = async (params?: {
|
||||
endDate?: string;
|
||||
range?: [string, string];
|
||||
startDate?: string;
|
||||
}): Promise<number> => {
|
||||
return lambdaClient.message.count.query(params);
|
||||
};
|
||||
|
||||
countWords = async (params?: {
|
||||
endDate?: string;
|
||||
range?: [string, string];
|
||||
startDate?: string;
|
||||
}): Promise<number> => {
|
||||
return lambdaClient.message.countWords.query(params);
|
||||
};
|
||||
|
||||
rankModels = async (): Promise<ModelRankItem[]> => {
|
||||
return lambdaClient.message.rankModels.query();
|
||||
};
|
||||
|
||||
getHeatmaps = async (): Promise<HeatmapsProps['data']> => {
|
||||
return lambdaClient.message.getHeatmaps.query();
|
||||
};
|
||||
|
||||
updateMessageError = async (id: string, error: ChatMessageError) => {
|
||||
return lambdaClient.message.update.mutate({ id, value: { error } });
|
||||
};
|
||||
|
||||
updateMessagePluginArguments = async (id: string, value: string | Record<string, any>) => {
|
||||
const args = typeof value === 'string' ? value : JSON.stringify(value);
|
||||
return lambdaClient.message.updateMessagePlugin.mutate({ id, value: { arguments: args } });
|
||||
};
|
||||
|
||||
updateMessage = async (
|
||||
id: string,
|
||||
value: Partial<UpdateMessageParams>,
|
||||
options?: { sessionId?: string | null; topicId?: string | null },
|
||||
): Promise<UpdateMessageResult> => {
|
||||
return lambdaClient.message.update.mutate({
|
||||
id,
|
||||
sessionId: options?.sessionId,
|
||||
topicId: options?.topicId,
|
||||
value,
|
||||
});
|
||||
};
|
||||
|
||||
updateMessageTranslate = async (id: string, translate: Partial<ChatTranslate> | false) => {
|
||||
return lambdaClient.message.updateTranslate.mutate({ id, value: translate as ChatTranslate });
|
||||
};
|
||||
|
||||
updateMessageTTS = async (id: string, tts: Partial<ChatTTS> | false) => {
|
||||
return lambdaClient.message.updateTTS.mutate({ id, value: tts });
|
||||
};
|
||||
|
||||
updateMessagePluginState = async (id: string, value: Record<string, any>) => {
|
||||
return lambdaClient.message.updatePluginState.mutate({ id, value });
|
||||
};
|
||||
|
||||
updateMessagePluginError = async (id: string, error: ChatMessagePluginError | null) => {
|
||||
return lambdaClient.message.updatePluginError.mutate({ id, value: error as any });
|
||||
};
|
||||
|
||||
updateMessageRAG = async (id: string, data: UpdateMessageRAGParams): Promise<void> => {
|
||||
return lambdaClient.message.updateMessageRAG.mutate({ id, value: data });
|
||||
};
|
||||
|
||||
removeMessage = async (id: string) => {
|
||||
return lambdaClient.message.removeMessage.mutate({ id });
|
||||
};
|
||||
|
||||
removeMessages = async (ids: string[]) => {
|
||||
return lambdaClient.message.removeMessages.mutate({ ids });
|
||||
};
|
||||
|
||||
removeMessagesByAssistant = async (sessionId: string, topicId?: string) => {
|
||||
return lambdaClient.message.removeMessagesByAssistant.mutate({
|
||||
sessionId: this.toDbSessionId(sessionId),
|
||||
topicId,
|
||||
});
|
||||
};
|
||||
|
||||
removeMessagesByGroup = async (groupId: string, topicId?: string) => {
|
||||
return lambdaClient.message.removeMessagesByGroup.mutate({
|
||||
groupId,
|
||||
topicId,
|
||||
});
|
||||
};
|
||||
|
||||
removeAllMessages = async () => {
|
||||
return lambdaClient.message.removeAllMessages.mutate();
|
||||
};
|
||||
|
||||
private toDbSessionId = (sessionId: string | undefined) => {
|
||||
return sessionId === INBOX_SESSION_ID ? null : sessionId;
|
||||
};
|
||||
|
||||
hasMessages = async (): Promise<boolean> => {
|
||||
const number = await this.countMessages();
|
||||
return number > 0;
|
||||
};
|
||||
|
||||
messageCountToCheckTrace = async (): Promise<boolean> => {
|
||||
const number = await this.countMessages();
|
||||
return number >= 4;
|
||||
};
|
||||
}
|
||||
|
||||
export const messageService = new MessageService();
|
||||
|
||||
@@ -2,11 +2,11 @@ import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { INBOX_SESSION_ID } from '@/const/session';
|
||||
|
||||
import { ServerService } from '../server';
|
||||
import { MessageService } from './index';
|
||||
|
||||
describe('ServerService', () => {
|
||||
describe('MessageService', () => {
|
||||
describe('toDbSessionId', () => {
|
||||
const service = new ServerService();
|
||||
const service = new MessageService();
|
||||
// @ts-ignore access private method for testing
|
||||
const toDbSessionId = service.toDbSessionId;
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { ChatTranslate, UIChatMessage } from '@lobechat/types';
|
||||
|
||||
import { INBOX_SESSION_ID } from '@/const/session';
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { labPreferSelectors } from '@/store/user/selectors';
|
||||
|
||||
import { IMessageService } from './type';
|
||||
|
||||
export class ServerService implements IMessageService {
|
||||
createMessage: IMessageService['createMessage'] = async ({ sessionId, ...params }) => {
|
||||
return lambdaClient.message.createMessage.mutate({
|
||||
...params,
|
||||
sessionId: sessionId ? this.toDbSessionId(sessionId) : undefined,
|
||||
});
|
||||
};
|
||||
|
||||
createNewMessage: IMessageService['createNewMessage'] = async ({ sessionId, ...params }) => {
|
||||
return lambdaClient.message.createNewMessage.mutate({
|
||||
...params,
|
||||
sessionId: sessionId ? this.toDbSessionId(sessionId) : undefined,
|
||||
});
|
||||
};
|
||||
|
||||
getMessages: IMessageService['getMessages'] = async (sessionId, topicId, groupId) => {
|
||||
// Get user lab preference for message grouping
|
||||
const useGroup = labPreferSelectors.enableAssistantMessageGroup(useUserStore.getState());
|
||||
|
||||
const data = await lambdaClient.message.getMessages.query({
|
||||
groupId,
|
||||
sessionId: this.toDbSessionId(sessionId),
|
||||
topicId,
|
||||
useGroup,
|
||||
});
|
||||
|
||||
return data as unknown as UIChatMessage[];
|
||||
};
|
||||
|
||||
getGroupMessages: IMessageService['getGroupMessages'] = async (groupId, topicId) => {
|
||||
// Get user lab preference for message grouping
|
||||
const useGroup = labPreferSelectors.enableAssistantMessageGroup(useUserStore.getState());
|
||||
|
||||
const data = await lambdaClient.message.getMessages.query({
|
||||
groupId,
|
||||
topicId,
|
||||
useGroup,
|
||||
});
|
||||
return data as unknown as UIChatMessage[];
|
||||
};
|
||||
|
||||
countMessages: IMessageService['countMessages'] = async (params) => {
|
||||
return lambdaClient.message.count.query(params);
|
||||
};
|
||||
|
||||
countWords: IMessageService['countWords'] = async (params) => {
|
||||
return lambdaClient.message.countWords.query(params);
|
||||
};
|
||||
|
||||
rankModels: IMessageService['rankModels'] = async () => {
|
||||
return lambdaClient.message.rankModels.query();
|
||||
};
|
||||
|
||||
getHeatmaps: IMessageService['getHeatmaps'] = async () => {
|
||||
return lambdaClient.message.getHeatmaps.query();
|
||||
};
|
||||
|
||||
updateMessageError: IMessageService['updateMessageError'] = async (id, error) => {
|
||||
return lambdaClient.message.update.mutate({ id, value: { error } });
|
||||
};
|
||||
|
||||
updateMessagePluginArguments: IMessageService['updateMessagePluginArguments'] = async (
|
||||
id,
|
||||
value,
|
||||
) => {
|
||||
const args = typeof value === 'string' ? value : JSON.stringify(value);
|
||||
return lambdaClient.message.updateMessagePlugin.mutate({ id, value: { arguments: args } });
|
||||
};
|
||||
|
||||
updateMessage: IMessageService['updateMessage'] = async (id, value, options) => {
|
||||
return lambdaClient.message.update.mutate({
|
||||
id,
|
||||
sessionId: options?.sessionId,
|
||||
topicId: options?.topicId,
|
||||
value,
|
||||
});
|
||||
};
|
||||
|
||||
updateMessageTranslate: IMessageService['updateMessageTranslate'] = async (id, translate) => {
|
||||
return lambdaClient.message.updateTranslate.mutate({ id, value: translate as ChatTranslate });
|
||||
};
|
||||
|
||||
updateMessageTTS: IMessageService['updateMessageTTS'] = async (id, tts) => {
|
||||
return lambdaClient.message.updateTTS.mutate({ id, value: tts });
|
||||
};
|
||||
|
||||
updateMessagePluginState: IMessageService['updateMessagePluginState'] = async (id, value) => {
|
||||
return lambdaClient.message.updatePluginState.mutate({ id, value });
|
||||
};
|
||||
|
||||
updateMessagePluginError: IMessageService['updateMessagePluginError'] = async (id, error) => {
|
||||
return lambdaClient.message.updatePluginError.mutate({ id, value: error as any });
|
||||
};
|
||||
|
||||
updateMessageRAG: IMessageService['updateMessageRAG'] = async (id, data) => {
|
||||
return lambdaClient.message.updateMessageRAG.mutate({ id, value: data });
|
||||
};
|
||||
|
||||
removeMessage: IMessageService['removeMessage'] = async (id) => {
|
||||
return lambdaClient.message.removeMessage.mutate({ id });
|
||||
};
|
||||
|
||||
removeMessages: IMessageService['removeMessages'] = async (ids) => {
|
||||
return lambdaClient.message.removeMessages.mutate({ ids });
|
||||
};
|
||||
|
||||
removeMessagesByAssistant: IMessageService['removeMessagesByAssistant'] = async (
|
||||
sessionId,
|
||||
topicId,
|
||||
) => {
|
||||
return lambdaClient.message.removeMessagesByAssistant.mutate({
|
||||
sessionId: this.toDbSessionId(sessionId),
|
||||
topicId,
|
||||
});
|
||||
};
|
||||
|
||||
removeMessagesByGroup: IMessageService['removeMessagesByGroup'] = async (groupId, topicId) => {
|
||||
return lambdaClient.message.removeMessagesByGroup.mutate({
|
||||
groupId,
|
||||
topicId,
|
||||
});
|
||||
};
|
||||
|
||||
removeAllMessages: IMessageService['removeAllMessages'] = async () => {
|
||||
return lambdaClient.message.removeAllMessages.mutate();
|
||||
};
|
||||
|
||||
private toDbSessionId = (sessionId: string | undefined) => {
|
||||
return sessionId === INBOX_SESSION_ID ? null : sessionId;
|
||||
};
|
||||
|
||||
hasMessages: IMessageService['hasMessages'] = async () => {
|
||||
const number = await this.countMessages();
|
||||
return number > 0;
|
||||
};
|
||||
|
||||
messageCountToCheckTrace: IMessageService['messageCountToCheckTrace'] = async () => {
|
||||
const number = await this.countMessages();
|
||||
return number >= 4;
|
||||
};
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import {
|
||||
ChatMessageError,
|
||||
ChatMessagePluginError,
|
||||
ChatTTS,
|
||||
ChatTranslate,
|
||||
CreateMessageParams,
|
||||
CreateMessageResult,
|
||||
ModelRankItem,
|
||||
UIChatMessage,
|
||||
UpdateMessageParams,
|
||||
UpdateMessageRAGParams,
|
||||
UpdateMessageResult,
|
||||
} from '@lobechat/types';
|
||||
import type { HeatmapsProps } from '@lobehub/charts';
|
||||
|
||||
/* eslint-disable typescript-sort-keys/interface */
|
||||
|
||||
export interface IMessageService {
|
||||
createMessage(data: CreateMessageParams): Promise<string>;
|
||||
createNewMessage(data: CreateMessageParams): Promise<CreateMessageResult>;
|
||||
|
||||
getMessages(sessionId: string, topicId?: string, groupId?: string): Promise<UIChatMessage[]>;
|
||||
getGroupMessages(groupId: string, topicId?: string): Promise<UIChatMessage[]>;
|
||||
countMessages(params?: {
|
||||
endDate?: string;
|
||||
range?: [string, string];
|
||||
startDate?: string;
|
||||
}): Promise<number>;
|
||||
countWords(params?: {
|
||||
endDate?: string;
|
||||
range?: [string, string];
|
||||
startDate?: string;
|
||||
}): Promise<number>;
|
||||
rankModels(): Promise<ModelRankItem[]>;
|
||||
getHeatmaps(): Promise<HeatmapsProps['data']>;
|
||||
updateMessageError(id: string, error: ChatMessageError): Promise<any>;
|
||||
updateMessage(
|
||||
id: string,
|
||||
message: Partial<UpdateMessageParams>,
|
||||
options?: { sessionId?: string | null; topicId?: string | null },
|
||||
): Promise<UpdateMessageResult>;
|
||||
updateMessageTTS(id: string, tts: Partial<ChatTTS> | false): Promise<any>;
|
||||
updateMessageTranslate(id: string, translate: Partial<ChatTranslate> | false): Promise<any>;
|
||||
updateMessagePluginState(id: string, value: Record<string, any>): Promise<any>;
|
||||
updateMessagePluginError(id: string, value: ChatMessagePluginError | null): Promise<any>;
|
||||
updateMessageRAG(id: string, value: UpdateMessageRAGParams): Promise<void>;
|
||||
updateMessagePluginArguments(id: string, value: string | Record<string, any>): Promise<any>;
|
||||
removeMessage(id: string): Promise<any>;
|
||||
removeMessages(ids: string[]): Promise<any>;
|
||||
removeMessagesByAssistant(assistantId: string, topicId?: string): Promise<any>;
|
||||
removeMessagesByGroup(groupId: string, topicId?: string): Promise<any>;
|
||||
removeAllMessages(): Promise<any>;
|
||||
messageCountToCheckTrace(): Promise<boolean>;
|
||||
hasMessages(): Promise<boolean>;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { describe } from 'vitest';
|
||||
import { testService } from '~test-utils';
|
||||
|
||||
import { PluginService } from './index';
|
||||
|
||||
describe('PluginService', () => {
|
||||
testService(PluginService, { checkAsync: false });
|
||||
});
|
||||
@@ -1,3 +1,54 @@
|
||||
import { ServerService } from './server';
|
||||
import { LobeTool } from '@lobechat/types';
|
||||
import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
||||
|
||||
export const pluginService = new ServerService();
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { LobeToolCustomPlugin } from '@/types/tool/plugin';
|
||||
|
||||
export interface InstallPluginParams {
|
||||
customParams?: Record<string, any>;
|
||||
identifier: string;
|
||||
manifest: LobeChatPluginManifest;
|
||||
settings?: Record<string, any>;
|
||||
type: 'plugin' | 'customPlugin';
|
||||
}
|
||||
|
||||
export class PluginService {
|
||||
installPlugin = async (plugin: InstallPluginParams): Promise<void> => {
|
||||
await lambdaClient.plugin.createOrInstallPlugin.mutate(plugin);
|
||||
};
|
||||
|
||||
getInstalledPlugins = (): Promise<LobeTool[]> => {
|
||||
return lambdaClient.plugin.getPlugins.query();
|
||||
};
|
||||
|
||||
uninstallPlugin = async (identifier: string): Promise<void> => {
|
||||
await lambdaClient.plugin.removePlugin.mutate({ id: identifier });
|
||||
};
|
||||
|
||||
createCustomPlugin = async (customPlugin: LobeToolCustomPlugin): Promise<void> => {
|
||||
await lambdaClient.plugin.createPlugin.mutate({ ...customPlugin, type: 'customPlugin' });
|
||||
};
|
||||
|
||||
updatePlugin = async (id: string, value: Partial<LobeToolCustomPlugin>): Promise<void> => {
|
||||
await lambdaClient.plugin.updatePlugin.mutate({
|
||||
customParams: value.customParams,
|
||||
id,
|
||||
manifest: value.manifest,
|
||||
settings: value.settings,
|
||||
});
|
||||
};
|
||||
|
||||
updatePluginManifest = async (id: string, manifest: LobeChatPluginManifest): Promise<void> => {
|
||||
await lambdaClient.plugin.updatePlugin.mutate({ id, manifest });
|
||||
};
|
||||
|
||||
removeAllPlugins = async (): Promise<void> => {
|
||||
await lambdaClient.plugin.removeAllPlugins.mutate();
|
||||
};
|
||||
|
||||
updatePluginSettings = async (id: string, settings: any, signal?: AbortSignal): Promise<void> => {
|
||||
await lambdaClient.plugin.updatePlugin.mutate({ id, settings }, { signal });
|
||||
};
|
||||
}
|
||||
|
||||
export const pluginService = new PluginService();
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
|
||||
import { IPluginService } from './type';
|
||||
|
||||
export class ServerService implements IPluginService {
|
||||
installPlugin: IPluginService['installPlugin'] = async (plugin) => {
|
||||
await lambdaClient.plugin.createOrInstallPlugin.mutate(plugin);
|
||||
};
|
||||
|
||||
getInstalledPlugins: IPluginService['getInstalledPlugins'] = () => {
|
||||
return lambdaClient.plugin.getPlugins.query();
|
||||
};
|
||||
|
||||
uninstallPlugin: IPluginService['uninstallPlugin'] = async (identifier) => {
|
||||
await lambdaClient.plugin.removePlugin.mutate({ id: identifier });
|
||||
};
|
||||
|
||||
createCustomPlugin: IPluginService['createCustomPlugin'] = async (customPlugin) => {
|
||||
await lambdaClient.plugin.createPlugin.mutate({ ...customPlugin, type: 'customPlugin' });
|
||||
};
|
||||
|
||||
updatePlugin: IPluginService['updatePlugin'] = async (id, value) => {
|
||||
await lambdaClient.plugin.updatePlugin.mutate({
|
||||
customParams: value.customParams,
|
||||
id,
|
||||
manifest: value.manifest,
|
||||
settings: value.settings,
|
||||
});
|
||||
};
|
||||
|
||||
updatePluginManifest: IPluginService['updatePluginManifest'] = async (id, manifest) => {
|
||||
await lambdaClient.plugin.updatePlugin.mutate({ id, manifest });
|
||||
};
|
||||
|
||||
removeAllPlugins: IPluginService['removeAllPlugins'] = async () => {
|
||||
await lambdaClient.plugin.removeAllPlugins.mutate();
|
||||
};
|
||||
|
||||
updatePluginSettings: IPluginService['updatePluginSettings'] = async (id, settings, signal) => {
|
||||
await lambdaClient.plugin.updatePlugin.mutate({ id, settings }, { signal });
|
||||
};
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { LobeTool } from '@lobechat/types';
|
||||
import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
||||
|
||||
import { LobeToolCustomPlugin } from '@/types/tool/plugin';
|
||||
|
||||
export interface InstallPluginParams {
|
||||
customParams?: Record<string, any>;
|
||||
identifier: string;
|
||||
manifest: LobeChatPluginManifest;
|
||||
settings?: Record<string, any>;
|
||||
type: 'plugin' | 'customPlugin';
|
||||
}
|
||||
|
||||
export interface IPluginService {
|
||||
createCustomPlugin: (customPlugin: LobeToolCustomPlugin) => Promise<void>;
|
||||
getInstalledPlugins: () => Promise<LobeTool[]>;
|
||||
installPlugin: (plugin: InstallPluginParams) => Promise<void>;
|
||||
removeAllPlugins: () => Promise<void>;
|
||||
uninstallPlugin: (identifier: string) => Promise<void>;
|
||||
updatePlugin: (id: string, value: Partial<LobeToolCustomPlugin>) => Promise<void>;
|
||||
updatePluginManifest: (id: string, manifest: LobeChatPluginManifest) => Promise<void>;
|
||||
updatePluginSettings: (id: string, settings: any, signal?: AbortSignal) => Promise<void>;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { describe } from 'vitest';
|
||||
import { testService } from '~test-utils';
|
||||
|
||||
import { SessionService } from './index';
|
||||
|
||||
describe('SessionService', () => {
|
||||
testService(SessionService, { checkAsync: false });
|
||||
});
|
||||
@@ -1,3 +1,146 @@
|
||||
import { ServerService } from './server';
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
|
||||
export const sessionService = new ServerService();
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { LobeAgentChatConfig, LobeAgentConfig } from '@/types/agent';
|
||||
import { MetaData } from '@/types/meta';
|
||||
import { BatchTaskResult } from '@/types/service';
|
||||
import {
|
||||
ChatSessionList,
|
||||
LobeAgentSession,
|
||||
LobeSessionType,
|
||||
LobeSessions,
|
||||
SessionGroupItem,
|
||||
SessionGroups,
|
||||
SessionRankItem,
|
||||
UpdateSessionParams,
|
||||
} from '@/types/session';
|
||||
|
||||
export class SessionService {
|
||||
hasSessions = async (): Promise<boolean> => {
|
||||
const result = await this.countSessions();
|
||||
return result === 0;
|
||||
};
|
||||
|
||||
createSession = async (
|
||||
type: LobeSessionType,
|
||||
data: Partial<LobeAgentSession>,
|
||||
): Promise<string> => {
|
||||
const { config, group, meta, ...session } = data;
|
||||
return lambdaClient.session.createSession.mutate({
|
||||
config: { ...config, ...meta } as any,
|
||||
session: { ...session, groupId: group },
|
||||
type,
|
||||
});
|
||||
};
|
||||
|
||||
cloneSession = (id: string, newTitle: string): Promise<string | undefined> => {
|
||||
return lambdaClient.session.cloneSession.mutate({ id, newTitle });
|
||||
};
|
||||
|
||||
getGroupedSessions = (): Promise<ChatSessionList> => {
|
||||
return lambdaClient.session.getGroupedSessions.query();
|
||||
};
|
||||
|
||||
countSessions = async (params?: {
|
||||
endDate?: string;
|
||||
range?: [string, string];
|
||||
startDate?: string;
|
||||
}): Promise<number> => {
|
||||
return lambdaClient.session.countSessions.query(params);
|
||||
};
|
||||
|
||||
rankSessions = async (limit?: number): Promise<SessionRankItem[]> => {
|
||||
return lambdaClient.session.rankSessions.query(limit);
|
||||
};
|
||||
|
||||
updateSession = (id: string, data: Partial<UpdateSessionParams>) => {
|
||||
const { group, pinned, meta, updatedAt } = data;
|
||||
return lambdaClient.session.updateSession.mutate({
|
||||
id,
|
||||
value: { groupId: group === 'default' ? null : group, pinned, ...meta, updatedAt },
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: Need to be fixed
|
||||
getSessionConfig = async (id: string): Promise<LobeAgentConfig> => {
|
||||
// @ts-ignore
|
||||
return lambdaClient.agent.getAgentConfig.query({ sessionId: id });
|
||||
};
|
||||
|
||||
updateSessionConfig = (
|
||||
id: string,
|
||||
config: PartialDeep<LobeAgentConfig>,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return lambdaClient.session.updateSessionConfig.mutate(
|
||||
{ id, value: config },
|
||||
{
|
||||
context: { showNotification: false },
|
||||
signal,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
updateSessionMeta = (id: string, meta: Partial<MetaData>, signal?: AbortSignal) => {
|
||||
return lambdaClient.session.updateSessionConfig.mutate({ id, value: meta }, { signal });
|
||||
};
|
||||
|
||||
updateSessionChatConfig = (
|
||||
id: string,
|
||||
value: Partial<LobeAgentChatConfig>,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return lambdaClient.session.updateSessionChatConfig.mutate({ id, value }, { signal });
|
||||
};
|
||||
|
||||
searchSessions = (keywords: string): Promise<LobeSessions> => {
|
||||
return lambdaClient.session.searchSessions.query({ keywords });
|
||||
};
|
||||
|
||||
removeSession = (id: string) => {
|
||||
return lambdaClient.session.removeSession.mutate({ id });
|
||||
};
|
||||
|
||||
removeAllSessions = () => {
|
||||
return lambdaClient.session.removeAllSessions.mutate();
|
||||
};
|
||||
|
||||
// ************************************** //
|
||||
// *********** SessionGroup *********** //
|
||||
// ************************************** //
|
||||
|
||||
createSessionGroup = (name: string, sort?: number): Promise<string> => {
|
||||
return lambdaClient.sessionGroup.createSessionGroup.mutate({ name, sort });
|
||||
};
|
||||
|
||||
getSessionGroups = (): Promise<SessionGroupItem[]> => {
|
||||
return lambdaClient.sessionGroup.getSessionGroup.query();
|
||||
};
|
||||
|
||||
/**
|
||||
* 需要废弃
|
||||
* @deprecated
|
||||
*/
|
||||
batchCreateSessionGroups = (groups: SessionGroups): Promise<BatchTaskResult> => {
|
||||
return Promise.resolve({ added: 0, ids: [], skips: [], success: true });
|
||||
};
|
||||
|
||||
removeSessionGroup = (id: string, removeChildren?: boolean) => {
|
||||
return lambdaClient.sessionGroup.removeSessionGroup.mutate({ id, removeChildren });
|
||||
};
|
||||
|
||||
removeSessionGroups = () => {
|
||||
return lambdaClient.sessionGroup.removeAllSessionGroups.mutate();
|
||||
};
|
||||
|
||||
updateSessionGroup = (id: string, value: Partial<SessionGroupItem>) => {
|
||||
return lambdaClient.sessionGroup.updateSessionGroup.mutate({ id, value });
|
||||
};
|
||||
|
||||
updateSessionGroupOrder = (sortMap: { id: string; sort: number }[]) => {
|
||||
return lambdaClient.sessionGroup.updateSessionGroupOrder.mutate({ sortMap });
|
||||
};
|
||||
}
|
||||
|
||||
export const sessionService = new SessionService();
|
||||
|
||||
@@ -1,260 +0,0 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { LobeSessionType } from '@/types/session';
|
||||
|
||||
import { ServerService } from './server';
|
||||
|
||||
vi.mock('@/libs/trpc/client', () => ({
|
||||
lambdaClient: {
|
||||
session: {
|
||||
createSession: { mutate: vi.fn() },
|
||||
batchCreateSessions: { mutate: vi.fn() },
|
||||
cloneSession: { mutate: vi.fn() },
|
||||
getGroupedSessions: { query: vi.fn() },
|
||||
countSessions: { query: vi.fn() },
|
||||
rankSessions: { query: vi.fn() },
|
||||
updateSession: { mutate: vi.fn() },
|
||||
updateSessionConfig: { mutate: vi.fn() },
|
||||
updateSessionChatConfig: { mutate: vi.fn() },
|
||||
getSessions: { query: vi.fn() },
|
||||
searchSessions: { query: vi.fn() },
|
||||
removeSession: { mutate: vi.fn() },
|
||||
removeAllSessions: { mutate: vi.fn() },
|
||||
},
|
||||
agent: {
|
||||
getAgentConfig: { query: vi.fn() },
|
||||
},
|
||||
sessionGroup: {
|
||||
createSessionGroup: { mutate: vi.fn() },
|
||||
getSessionGroup: { query: vi.fn() },
|
||||
removeSessionGroup: { mutate: vi.fn() },
|
||||
removeAllSessionGroups: { mutate: vi.fn() },
|
||||
updateSessionGroup: { mutate: vi.fn() },
|
||||
updateSessionGroupOrder: { mutate: vi.fn() },
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe('ServerService', () => {
|
||||
let service: ServerService;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
service = new ServerService();
|
||||
});
|
||||
|
||||
it('hasSessions should return true if count is 0', async () => {
|
||||
vi.mocked(lambdaClient.session.countSessions.query).mockResolvedValue(0);
|
||||
const result = await service.hasSessions();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('createSession should call lambdaClient with correct params', async () => {
|
||||
const mockData = {
|
||||
config: {
|
||||
model: 'gpt-3.5',
|
||||
params: {},
|
||||
systemRole: '',
|
||||
chatConfig: {
|
||||
autoCreateTopicThreshold: 2,
|
||||
compressThreshold: 10,
|
||||
enableAutoCreateTopic: true,
|
||||
enableCompressThreshold: true,
|
||||
maxTokens: 2000,
|
||||
model: 'gpt-3.5-turbo',
|
||||
params: {},
|
||||
temperature: 0.7,
|
||||
title: 'test',
|
||||
},
|
||||
tts: {
|
||||
showAllLocaleVoice: false,
|
||||
sttLocale: 'auto',
|
||||
ttsService: 'openai' as const,
|
||||
voice: {
|
||||
model: 'tts-1',
|
||||
name: 'alloy',
|
||||
type: 'tts',
|
||||
openai: 'voice-id',
|
||||
},
|
||||
},
|
||||
openingQuestions: ['Question 1', 'Question 2'],
|
||||
openingMessage: 'Hello, I am [LobeChat](https://github.com/lobehub/lobe-chat).',
|
||||
},
|
||||
group: 'testGroup',
|
||||
meta: { description: 'test' },
|
||||
title: 'Test Session',
|
||||
};
|
||||
|
||||
await service.createSession(LobeSessionType.Agent, mockData);
|
||||
|
||||
expect(lambdaClient.session.createSession.mutate).toBeCalledWith({
|
||||
config: { ...mockData.config, description: 'test' },
|
||||
session: { title: 'Test Session', groupId: 'testGroup' },
|
||||
type: LobeSessionType.Agent,
|
||||
});
|
||||
});
|
||||
|
||||
it('batchCreateSessions should call lambdaClient', async () => {
|
||||
const mockSessions = [
|
||||
{
|
||||
id: '1',
|
||||
title: 'Test',
|
||||
config: {
|
||||
model: 'gpt-3.5',
|
||||
params: {},
|
||||
systemRole: '',
|
||||
chatConfig: {
|
||||
autoCreateTopicThreshold: 2,
|
||||
compressThreshold: 10,
|
||||
enableAutoCreateTopic: true,
|
||||
enableCompressThreshold: true,
|
||||
maxTokens: 2000,
|
||||
model: 'gpt-3.5-turbo',
|
||||
params: {},
|
||||
temperature: 0.7,
|
||||
title: 'test',
|
||||
},
|
||||
tts: {
|
||||
showAllLocaleVoice: false,
|
||||
sttLocale: 'auto',
|
||||
ttsService: 'openai' as const,
|
||||
voice: {
|
||||
model: 'tts-1',
|
||||
name: 'alloy',
|
||||
type: 'tts',
|
||||
openai: 'voice-id',
|
||||
},
|
||||
},
|
||||
},
|
||||
createdAt: new Date(),
|
||||
meta: { description: 'test' },
|
||||
model: 'gpt-3.5',
|
||||
type: LobeSessionType.Agent,
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
];
|
||||
|
||||
await service.batchCreateSessions(mockSessions as any);
|
||||
expect(lambdaClient.session.batchCreateSessions.mutate).toBeCalledWith(mockSessions);
|
||||
});
|
||||
|
||||
it('cloneSession should call lambdaClient', async () => {
|
||||
await service.cloneSession('123', 'New Title');
|
||||
expect(lambdaClient.session.cloneSession.mutate).toBeCalledWith({
|
||||
id: '123',
|
||||
newTitle: 'New Title',
|
||||
});
|
||||
});
|
||||
|
||||
it('getGroupedSessions should call lambdaClient', async () => {
|
||||
await service.getGroupedSessions();
|
||||
expect(lambdaClient.session.getGroupedSessions.query).toBeCalled();
|
||||
});
|
||||
|
||||
it('countSessions should call lambdaClient with params', async () => {
|
||||
const params = { startDate: '2023-01-01' };
|
||||
await service.countSessions(params);
|
||||
expect(lambdaClient.session.countSessions.query).toBeCalledWith(params);
|
||||
});
|
||||
|
||||
it('rankSessions should call lambdaClient with limit', async () => {
|
||||
await service.rankSessions(10);
|
||||
expect(lambdaClient.session.rankSessions.query).toBeCalledWith(10);
|
||||
});
|
||||
|
||||
it('updateSession should call lambdaClient with correct params', async () => {
|
||||
const mockData = {
|
||||
group: 'default',
|
||||
pinned: true,
|
||||
meta: { description: 'bar' },
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
await service.updateSession('123', mockData);
|
||||
|
||||
expect(lambdaClient.session.updateSession.mutate).toBeCalledWith({
|
||||
id: '123',
|
||||
value: {
|
||||
groupId: null,
|
||||
pinned: true,
|
||||
description: 'bar',
|
||||
updatedAt: mockData.updatedAt,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('getSessionConfig should call lambdaClient', async () => {
|
||||
await service.getSessionConfig('123');
|
||||
expect(lambdaClient.agent.getAgentConfig.query).toBeCalledWith({ sessionId: '123' });
|
||||
});
|
||||
|
||||
it('updateSessionConfig should call lambdaClient', async () => {
|
||||
const config = { model: 'gpt-4' };
|
||||
const signal = new AbortController().signal;
|
||||
await service.updateSessionConfig('123', config, signal);
|
||||
expect(lambdaClient.session.updateSessionConfig.mutate).toBeCalledWith(
|
||||
{ id: '123', value: config },
|
||||
{
|
||||
signal,
|
||||
context: { showNotification: false },
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('getSessionsByType should call lambdaClient', async () => {
|
||||
await service.getSessionsByType('all');
|
||||
expect(lambdaClient.session.getSessions.query).toBeCalledWith({});
|
||||
});
|
||||
|
||||
it('searchSessions should call lambdaClient with keywords', async () => {
|
||||
await service.searchSessions('test');
|
||||
expect(lambdaClient.session.searchSessions.query).toBeCalledWith({ keywords: 'test' });
|
||||
});
|
||||
|
||||
it('removeSession should call lambdaClient', async () => {
|
||||
await service.removeSession('123');
|
||||
expect(lambdaClient.session.removeSession.mutate).toBeCalledWith({ id: '123' });
|
||||
});
|
||||
|
||||
it('removeAllSessions should call lambdaClient', async () => {
|
||||
await service.removeAllSessions();
|
||||
expect(lambdaClient.session.removeAllSessions.mutate).toBeCalled();
|
||||
});
|
||||
|
||||
it('createSessionGroup should call lambdaClient', async () => {
|
||||
await service.createSessionGroup('Test Group', 1);
|
||||
expect(lambdaClient.sessionGroup.createSessionGroup.mutate).toBeCalledWith({
|
||||
name: 'Test Group',
|
||||
sort: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('getSessionGroups should call lambdaClient', async () => {
|
||||
await service.getSessionGroups();
|
||||
expect(lambdaClient.sessionGroup.getSessionGroup.query).toBeCalled();
|
||||
});
|
||||
|
||||
it('removeSessionGroup should call lambdaClient', async () => {
|
||||
await service.removeSessionGroup('123', true);
|
||||
expect(lambdaClient.sessionGroup.removeSessionGroup.mutate).toBeCalledWith({
|
||||
id: '123',
|
||||
removeChildren: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('updateSessionGroup should call lambdaClient', async () => {
|
||||
const value = { name: 'Updated Group' };
|
||||
await service.updateSessionGroup('123', value);
|
||||
expect(lambdaClient.sessionGroup.updateSessionGroup.mutate).toBeCalledWith({
|
||||
id: '123',
|
||||
value,
|
||||
});
|
||||
});
|
||||
|
||||
it('updateSessionGroupOrder should call lambdaClient', async () => {
|
||||
const sortMap = [{ id: '123', sort: 1 }];
|
||||
await service.updateSessionGroupOrder(sortMap);
|
||||
expect(lambdaClient.sessionGroup.updateSessionGroupOrder.mutate).toBeCalledWith({ sortMap });
|
||||
});
|
||||
});
|
||||
@@ -1,125 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
|
||||
import { ISessionService } from './type';
|
||||
|
||||
export class ServerService implements ISessionService {
|
||||
hasSessions: ISessionService['hasSessions'] = async () => {
|
||||
const result = await this.countSessions();
|
||||
return result === 0;
|
||||
};
|
||||
|
||||
createSession: ISessionService['createSession'] = async (type, data) => {
|
||||
const { config, group, meta, ...session } = data;
|
||||
return lambdaClient.session.createSession.mutate({
|
||||
config: { ...config, ...meta } as any,
|
||||
session: { ...session, groupId: group },
|
||||
type,
|
||||
});
|
||||
};
|
||||
|
||||
batchCreateSessions: ISessionService['batchCreateSessions'] = async (importSessions) => {
|
||||
// TODO: remove any
|
||||
const data = await lambdaClient.session.batchCreateSessions.mutate(importSessions as any);
|
||||
console.log(data);
|
||||
return data;
|
||||
};
|
||||
|
||||
cloneSession: ISessionService['cloneSession'] = (id, newTitle) => {
|
||||
return lambdaClient.session.cloneSession.mutate({ id, newTitle });
|
||||
};
|
||||
|
||||
getGroupedSessions: ISessionService['getGroupedSessions'] = () => {
|
||||
return lambdaClient.session.getGroupedSessions.query();
|
||||
};
|
||||
|
||||
countSessions: ISessionService['countSessions'] = async (params) => {
|
||||
return lambdaClient.session.countSessions.query(params);
|
||||
};
|
||||
|
||||
rankSessions: ISessionService['rankSessions'] = async (limit) => {
|
||||
return lambdaClient.session.rankSessions.query(limit);
|
||||
};
|
||||
|
||||
updateSession: ISessionService['updateSession'] = (id, data) => {
|
||||
const { group, pinned, meta, updatedAt } = data;
|
||||
return lambdaClient.session.updateSession.mutate({
|
||||
id,
|
||||
value: { groupId: group === 'default' ? null : group, pinned, ...meta, updatedAt },
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: Need to be fixed
|
||||
// @ts-ignore
|
||||
getSessionConfig: ISessionService['getSessionConfig'] = async (id) => {
|
||||
return lambdaClient.agent.getAgentConfig.query({ sessionId: id });
|
||||
};
|
||||
|
||||
updateSessionConfig: ISessionService['updateSessionConfig'] = (id, config, signal) => {
|
||||
return lambdaClient.session.updateSessionConfig.mutate(
|
||||
{ id, value: config },
|
||||
{
|
||||
context: { showNotification: false },
|
||||
signal,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
updateSessionMeta: ISessionService['updateSessionMeta'] = (id, meta, signal) => {
|
||||
return lambdaClient.session.updateSessionConfig.mutate({ id, value: meta }, { signal });
|
||||
};
|
||||
|
||||
updateSessionChatConfig: ISessionService['updateSessionChatConfig'] = (id, value, signal) => {
|
||||
return lambdaClient.session.updateSessionChatConfig.mutate({ id, value }, { signal });
|
||||
};
|
||||
|
||||
// TODO: need be fixed
|
||||
// @ts-ignore
|
||||
getSessionsByType: ISessionService['getSessionsByType'] = (_type = 'all') => {
|
||||
return lambdaClient.session.getSessions.query({});
|
||||
};
|
||||
|
||||
searchSessions: ISessionService['searchSessions'] = (keywords) => {
|
||||
return lambdaClient.session.searchSessions.query({ keywords });
|
||||
};
|
||||
|
||||
removeSession: ISessionService['removeSession'] = (id) => {
|
||||
return lambdaClient.session.removeSession.mutate({ id });
|
||||
};
|
||||
|
||||
removeAllSessions: ISessionService['removeAllSessions'] = () => {
|
||||
return lambdaClient.session.removeAllSessions.mutate();
|
||||
};
|
||||
|
||||
// ************************************** //
|
||||
// *********** SessionGroup *********** //
|
||||
// ************************************** //
|
||||
|
||||
createSessionGroup: ISessionService['createSessionGroup'] = (name, sort) => {
|
||||
return lambdaClient.sessionGroup.createSessionGroup.mutate({ name, sort });
|
||||
};
|
||||
|
||||
getSessionGroups: ISessionService['getSessionGroups'] = () => {
|
||||
return lambdaClient.sessionGroup.getSessionGroup.query();
|
||||
};
|
||||
|
||||
batchCreateSessionGroups: ISessionService['batchCreateSessionGroups'] = (_groups) => {
|
||||
return Promise.resolve({ added: 0, ids: [], skips: [], success: true });
|
||||
};
|
||||
|
||||
removeSessionGroup: ISessionService['removeSessionGroup'] = (id, removeChildren) => {
|
||||
return lambdaClient.sessionGroup.removeSessionGroup.mutate({ id, removeChildren });
|
||||
};
|
||||
|
||||
removeSessionGroups: ISessionService['removeSessionGroups'] = () => {
|
||||
return lambdaClient.sessionGroup.removeAllSessionGroups.mutate();
|
||||
};
|
||||
|
||||
updateSessionGroup: ISessionService['updateSessionGroup'] = (id, value) => {
|
||||
return lambdaClient.sessionGroup.updateSessionGroup.mutate({ id, value });
|
||||
};
|
||||
|
||||
updateSessionGroupOrder: ISessionService['updateSessionGroupOrder'] = (sortMap) => {
|
||||
return lambdaClient.sessionGroup.updateSessionGroupOrder.mutate({ sortMap });
|
||||
};
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/* eslint-disable typescript-sort-keys/interface */
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
|
||||
import { LobeAgentChatConfig, LobeAgentConfig } from '@/types/agent';
|
||||
import { MetaData } from '@/types/meta';
|
||||
import { BatchTaskResult } from '@/types/service';
|
||||
import {
|
||||
ChatSessionList,
|
||||
LobeAgentSession,
|
||||
LobeSessionType,
|
||||
LobeSessions,
|
||||
SessionGroupItem,
|
||||
SessionGroups,
|
||||
SessionRankItem,
|
||||
UpdateSessionParams,
|
||||
} from '@/types/session';
|
||||
|
||||
export interface ISessionService {
|
||||
hasSessions(): Promise<boolean>;
|
||||
createSession(type: LobeSessionType, defaultValue: Partial<LobeAgentSession>): Promise<string>;
|
||||
|
||||
/**
|
||||
* 需要废弃
|
||||
* @deprecated
|
||||
*/
|
||||
batchCreateSessions(importSessions: LobeSessions): Promise<any>;
|
||||
cloneSession(id: string, newTitle: string): Promise<string | undefined>;
|
||||
|
||||
getGroupedSessions(): Promise<ChatSessionList>;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
getSessionsByType(type?: 'agent' | 'group' | 'all'): Promise<LobeSessions>;
|
||||
countSessions(params?: {
|
||||
endDate?: string;
|
||||
range?: [string, string];
|
||||
startDate?: string;
|
||||
}): Promise<number>;
|
||||
rankSessions(limit?: number): Promise<SessionRankItem[]>;
|
||||
searchSessions(keyword: string): Promise<LobeSessions>;
|
||||
|
||||
updateSession(id: string, data: Partial<UpdateSessionParams>): Promise<any>;
|
||||
|
||||
getSessionConfig(id: string): Promise<LobeAgentConfig>;
|
||||
updateSessionConfig(
|
||||
id: string,
|
||||
config: PartialDeep<LobeAgentConfig>,
|
||||
signal?: AbortSignal,
|
||||
): Promise<any>;
|
||||
|
||||
updateSessionMeta(id: string, meta: Partial<MetaData>, signal?: AbortSignal): Promise<any>;
|
||||
|
||||
updateSessionChatConfig(
|
||||
id: string,
|
||||
config: Partial<LobeAgentChatConfig>,
|
||||
signal?: AbortSignal,
|
||||
): Promise<any>;
|
||||
|
||||
removeSession(id: string): Promise<any>;
|
||||
removeAllSessions(): Promise<any>;
|
||||
|
||||
// ************************************** //
|
||||
// *********** SessionGroup *********** //
|
||||
// ************************************** //
|
||||
|
||||
createSessionGroup(name: string, sort?: number): Promise<string>;
|
||||
|
||||
/**
|
||||
* 需要废弃
|
||||
* @deprecated
|
||||
*/
|
||||
batchCreateSessionGroups(groups: SessionGroups): Promise<BatchTaskResult>;
|
||||
|
||||
getSessionGroups(): Promise<SessionGroupItem[]>;
|
||||
|
||||
updateSessionGroup(id: string, data: Partial<SessionGroupItem>): Promise<any>;
|
||||
updateSessionGroupOrder(sortMap: { id: string; sort: number }[]): Promise<any>;
|
||||
|
||||
removeSessionGroup(id: string, removeChildren?: boolean): Promise<any>;
|
||||
removeSessionGroups(): Promise<any>;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { describe } from 'vitest';
|
||||
import { testService } from '~test-utils';
|
||||
|
||||
import { ThreadService } from './index';
|
||||
|
||||
describe('ThreadService', () => {
|
||||
testService(ThreadService, { checkAsync: false });
|
||||
});
|
||||
@@ -1,3 +1,39 @@
|
||||
import { ServerService } from './server';
|
||||
import { CreateMessageParams } from '@lobechat/types';
|
||||
|
||||
export const threadService = new ServerService();
|
||||
import { INBOX_SESSION_ID } from '@/const/session';
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { CreateThreadParams, ThreadItem } from '@/types/topic';
|
||||
|
||||
interface CreateThreadWithMessageParams extends CreateThreadParams {
|
||||
message: CreateMessageParams;
|
||||
}
|
||||
|
||||
export class ThreadService {
|
||||
getThreads = (topicId: string): Promise<ThreadItem[]> => {
|
||||
return lambdaClient.thread.getThreads.query({ topicId });
|
||||
};
|
||||
|
||||
createThreadWithMessage = async ({
|
||||
message,
|
||||
...params
|
||||
}: CreateThreadWithMessageParams): Promise<{ messageId: string; threadId: string }> => {
|
||||
return lambdaClient.thread.createThreadWithMessage.mutate({
|
||||
...params,
|
||||
message: { ...message, sessionId: this.toDbSessionId(message.sessionId) },
|
||||
});
|
||||
};
|
||||
|
||||
updateThread = async (id: string, data: Partial<ThreadItem>) => {
|
||||
return lambdaClient.thread.updateThread.mutate({ id, value: data });
|
||||
};
|
||||
|
||||
removeThread = async (id: string) => {
|
||||
return lambdaClient.thread.removeThread.mutate({ id });
|
||||
};
|
||||
|
||||
private toDbSessionId = (sessionId: string | undefined) => {
|
||||
return sessionId === INBOX_SESSION_ID ? null : sessionId;
|
||||
};
|
||||
}
|
||||
|
||||
export const threadService = new ThreadService();
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { INBOX_SESSION_ID } from '@/const/session';
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
|
||||
import { IThreadService } from './type';
|
||||
|
||||
export class ServerService implements IThreadService {
|
||||
getThreads: IThreadService['getThreads'] = (topicId) => {
|
||||
return lambdaClient.thread.getThreads.query({ topicId });
|
||||
};
|
||||
|
||||
createThreadWithMessage: IThreadService['createThreadWithMessage'] = async ({
|
||||
message,
|
||||
...params
|
||||
}) => {
|
||||
return lambdaClient.thread.createThreadWithMessage.mutate({
|
||||
...params,
|
||||
message: { ...message, sessionId: this.toDbSessionId(message.sessionId) },
|
||||
});
|
||||
};
|
||||
|
||||
updateThread: IThreadService['updateThread'] = async (id, data) => {
|
||||
return lambdaClient.thread.updateThread.mutate({ id, value: data });
|
||||
};
|
||||
|
||||
removeThread: IThreadService['removeThread'] = async (id) => {
|
||||
return lambdaClient.thread.removeThread.mutate({ id });
|
||||
};
|
||||
|
||||
private toDbSessionId = (sessionId: string | undefined) => {
|
||||
return sessionId === INBOX_SESSION_ID ? null : sessionId;
|
||||
};
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/* eslint-disable typescript-sort-keys/interface */
|
||||
import { CreateMessageParams } from '@lobechat/types';
|
||||
|
||||
import { CreateThreadParams, ThreadItem } from '@/types/topic';
|
||||
|
||||
interface CreateThreadWithMessageParams extends CreateThreadParams {
|
||||
message: CreateMessageParams;
|
||||
}
|
||||
|
||||
export interface IThreadService {
|
||||
getThreads(topicId: string): Promise<ThreadItem[]>;
|
||||
|
||||
createThreadWithMessage({
|
||||
message,
|
||||
...params
|
||||
}: CreateThreadWithMessageParams): Promise<{ messageId: string; threadId: string }>;
|
||||
|
||||
updateThread(id: string, data: Partial<ThreadItem>): Promise<any>;
|
||||
//
|
||||
removeThread(id: string): Promise<any>;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { describe } from 'vitest';
|
||||
import { testService } from '~test-utils';
|
||||
|
||||
import { TopicService } from './index';
|
||||
|
||||
describe('TopicService', () => {
|
||||
testService(TopicService, { checkAsync: false });
|
||||
});
|
||||
@@ -1,3 +1,77 @@
|
||||
import { ServerService } from './server';
|
||||
import { INBOX_SESSION_ID } from '@/const/session';
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { BatchTaskResult } from '@/types/service';
|
||||
import { ChatTopic, CreateTopicParams, QueryTopicParams, TopicRankItem } from '@/types/topic';
|
||||
|
||||
export const topicService = new ServerService();
|
||||
export class TopicService {
|
||||
createTopic = (params: CreateTopicParams): Promise<string> => {
|
||||
return lambdaClient.topic.createTopic.mutate({
|
||||
...params,
|
||||
sessionId: this.toDbSessionId(params.sessionId),
|
||||
});
|
||||
};
|
||||
|
||||
batchCreateTopics = (importTopics: ChatTopic[]): Promise<BatchTaskResult> => {
|
||||
return lambdaClient.topic.batchCreateTopics.mutate(importTopics);
|
||||
};
|
||||
|
||||
cloneTopic = (id: string, newTitle?: string): Promise<string> => {
|
||||
return lambdaClient.topic.cloneTopic.mutate({ id, newTitle });
|
||||
};
|
||||
|
||||
getTopics = (params: QueryTopicParams): Promise<ChatTopic[]> => {
|
||||
return lambdaClient.topic.getTopics.query({
|
||||
...params,
|
||||
containerId: this.toDbSessionId(params.containerId),
|
||||
}) as any;
|
||||
};
|
||||
|
||||
getAllTopics = (): Promise<ChatTopic[]> => {
|
||||
return lambdaClient.topic.getAllTopics.query() as any;
|
||||
};
|
||||
|
||||
countTopics = async (params?: {
|
||||
endDate?: string;
|
||||
range?: [string, string];
|
||||
startDate?: string;
|
||||
}): Promise<number> => {
|
||||
return lambdaClient.topic.countTopics.query(params);
|
||||
};
|
||||
|
||||
rankTopics = async (limit?: number): Promise<TopicRankItem[]> => {
|
||||
return lambdaClient.topic.rankTopics.query(limit);
|
||||
};
|
||||
|
||||
searchTopics = (keywords: string, sessionId?: string, groupId?: string): Promise<ChatTopic[]> => {
|
||||
return lambdaClient.topic.searchTopics.query({
|
||||
groupId,
|
||||
keywords,
|
||||
sessionId: this.toDbSessionId(sessionId),
|
||||
}) as any;
|
||||
};
|
||||
|
||||
updateTopic = (id: string, data: Partial<ChatTopic>) => {
|
||||
return lambdaClient.topic.updateTopic.mutate({ id, value: data });
|
||||
};
|
||||
|
||||
removeTopic = (id: string) => {
|
||||
return lambdaClient.topic.removeTopic.mutate({ id });
|
||||
};
|
||||
|
||||
removeTopics = (sessionId: string) => {
|
||||
return lambdaClient.topic.batchDeleteBySessionId.mutate({ id: this.toDbSessionId(sessionId) });
|
||||
};
|
||||
|
||||
batchRemoveTopics = (topics: string[]) => {
|
||||
return lambdaClient.topic.batchDelete.mutate({ ids: topics });
|
||||
};
|
||||
|
||||
removeAllTopic = () => {
|
||||
return lambdaClient.topic.removeAllTopics.mutate();
|
||||
};
|
||||
|
||||
private toDbSessionId = (sessionId?: string | null) =>
|
||||
sessionId === INBOX_SESSION_ID ? null : sessionId;
|
||||
}
|
||||
|
||||
export const topicService = new TopicService();
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { INBOX_SESSION_ID } from '@/const/session';
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { ITopicService } from '@/services/topic/type';
|
||||
|
||||
export class ServerService implements ITopicService {
|
||||
createTopic: ITopicService['createTopic'] = (params) =>
|
||||
lambdaClient.topic.createTopic.mutate({
|
||||
...params,
|
||||
sessionId: this.toDbSessionId(params.sessionId),
|
||||
});
|
||||
|
||||
batchCreateTopics: ITopicService['batchCreateTopics'] = (importTopics) =>
|
||||
lambdaClient.topic.batchCreateTopics.mutate(importTopics);
|
||||
|
||||
cloneTopic: ITopicService['cloneTopic'] = (id, newTitle) =>
|
||||
lambdaClient.topic.cloneTopic.mutate({ id, newTitle });
|
||||
|
||||
getTopics: ITopicService['getTopics'] = (params) =>
|
||||
lambdaClient.topic.getTopics.query({
|
||||
...params,
|
||||
containerId: this.toDbSessionId(params.containerId),
|
||||
}) as any;
|
||||
|
||||
getAllTopics: ITopicService['getAllTopics'] = () =>
|
||||
lambdaClient.topic.getAllTopics.query() as any;
|
||||
|
||||
countTopics: ITopicService['countTopics'] = async (params) => {
|
||||
return lambdaClient.topic.countTopics.query(params);
|
||||
};
|
||||
|
||||
rankTopics: ITopicService['rankTopics'] = async (limit) => {
|
||||
return lambdaClient.topic.rankTopics.query(limit);
|
||||
};
|
||||
|
||||
searchTopics: ITopicService['searchTopics'] = (keywords, sessionId) =>
|
||||
lambdaClient.topic.searchTopics.query({
|
||||
keywords,
|
||||
sessionId: this.toDbSessionId(sessionId),
|
||||
}) as any;
|
||||
|
||||
updateTopic: ITopicService['updateTopic'] = (id, data) =>
|
||||
lambdaClient.topic.updateTopic.mutate({ id, value: data });
|
||||
|
||||
removeTopic: ITopicService['removeTopic'] = (id) => lambdaClient.topic.removeTopic.mutate({ id });
|
||||
|
||||
removeTopics: ITopicService['removeTopics'] = (sessionId) =>
|
||||
lambdaClient.topic.batchDeleteBySessionId.mutate({ id: this.toDbSessionId(sessionId) });
|
||||
|
||||
batchRemoveTopics: ITopicService['batchRemoveTopics'] = (topics) =>
|
||||
lambdaClient.topic.batchDelete.mutate({ ids: topics });
|
||||
|
||||
removeAllTopic: ITopicService['removeAllTopic'] = () =>
|
||||
lambdaClient.topic.removeAllTopics.mutate();
|
||||
|
||||
private toDbSessionId = (sessionId?: string | null) =>
|
||||
sessionId === INBOX_SESSION_ID ? null : sessionId;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/* eslint-disable typescript-sort-keys/interface */
|
||||
import { BatchTaskResult } from '@/types/service';
|
||||
import { ChatTopic, TopicRankItem } from '@/types/topic';
|
||||
|
||||
export interface CreateTopicParams {
|
||||
favorite?: boolean;
|
||||
groupId?: string | null;
|
||||
messages?: string[];
|
||||
sessionId?: string | null;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface QueryTopicParams {
|
||||
current?: number;
|
||||
containerId?: string | null; // sessionId or groupId
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
export interface ITopicService {
|
||||
createTopic(params: CreateTopicParams): Promise<string>;
|
||||
batchCreateTopics(importTopics: ChatTopic[]): Promise<BatchTaskResult>;
|
||||
cloneTopic(id: string, newTitle?: string): Promise<string>;
|
||||
|
||||
getTopics(params: QueryTopicParams): Promise<ChatTopic[]>;
|
||||
getAllTopics(): Promise<ChatTopic[]>;
|
||||
countTopics(params?: {
|
||||
endDate?: string;
|
||||
range?: [string, string];
|
||||
startDate?: string;
|
||||
}): Promise<number>;
|
||||
rankTopics(limit?: number): Promise<TopicRankItem[]>;
|
||||
searchTopics(keyword: string, sessionId?: string, groupId?: string): Promise<ChatTopic[]>;
|
||||
|
||||
updateTopic(id: string, data: Partial<ChatTopic>): Promise<any>;
|
||||
|
||||
removeTopic(id: string): Promise<any>;
|
||||
removeTopics(sessionId: string): Promise<any>;
|
||||
batchRemoveTopics(topics: string[]): Promise<any>;
|
||||
removeAllTopic(): Promise<any>;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { describe } from 'vitest';
|
||||
import { testService } from '~test-utils';
|
||||
|
||||
import { UserService } from './index';
|
||||
|
||||
describe('UserService', () => {
|
||||
testService(UserService);
|
||||
});
|
||||
@@ -1,3 +1,54 @@
|
||||
import { ServerService } from './server';
|
||||
import type { AdapterAccount } from 'next-auth/adapters';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
|
||||
export const userService = new ServerService();
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { UserGuide, UserInitializationState, UserPreference } from '@/types/user';
|
||||
import { UserSettings } from '@/types/user/settings';
|
||||
|
||||
export class UserService {
|
||||
getUserRegistrationDuration = async (): Promise<{
|
||||
createdAt: string;
|
||||
duration: number;
|
||||
updatedAt: string;
|
||||
}> => {
|
||||
return lambdaClient.user.getUserRegistrationDuration.query();
|
||||
};
|
||||
|
||||
getUserState = async (): Promise<UserInitializationState> => {
|
||||
return lambdaClient.user.getUserState.query();
|
||||
};
|
||||
|
||||
getUserSSOProviders = async (): Promise<AdapterAccount[]> => {
|
||||
return lambdaClient.user.getUserSSOProviders.query();
|
||||
};
|
||||
|
||||
unlinkSSOProvider = async (provider: string, providerAccountId: string) => {
|
||||
return lambdaClient.user.unlinkSSOProvider.mutate({ provider, providerAccountId });
|
||||
};
|
||||
|
||||
makeUserOnboarded = async () => {
|
||||
return lambdaClient.user.makeUserOnboarded.mutate();
|
||||
};
|
||||
|
||||
updateAvatar = async (avatar: string) => {
|
||||
return lambdaClient.user.updateAvatar.mutate(avatar);
|
||||
};
|
||||
|
||||
updatePreference = async (preference: Partial<UserPreference>) => {
|
||||
return lambdaClient.user.updatePreference.mutate(preference);
|
||||
};
|
||||
|
||||
updateGuide = async (guide: Partial<UserGuide>) => {
|
||||
return lambdaClient.user.updateGuide.mutate(guide);
|
||||
};
|
||||
|
||||
updateUserSettings = async (value: PartialDeep<UserSettings>, signal?: AbortSignal) => {
|
||||
return lambdaClient.user.updateSettings.mutate(value, { signal });
|
||||
};
|
||||
|
||||
resetUserSettings = async () => {
|
||||
return lambdaClient.user.resetSettings.mutate();
|
||||
};
|
||||
}
|
||||
|
||||
export const userService = new UserService();
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { UserInitializationState, UserPreference } from '@/types/user';
|
||||
import { UserSettings } from '@/types/user/settings';
|
||||
|
||||
import { ServerService } from './server';
|
||||
|
||||
vi.mock('@/libs/trpc/client', () => ({
|
||||
lambdaClient: {
|
||||
user: {
|
||||
getUserRegistrationDuration: {
|
||||
query: vi.fn(),
|
||||
},
|
||||
getUserState: {
|
||||
query: vi.fn(),
|
||||
},
|
||||
getUserSSOProviders: {
|
||||
query: vi.fn(),
|
||||
},
|
||||
unlinkSSOProvider: {
|
||||
mutate: vi.fn(),
|
||||
},
|
||||
makeUserOnboarded: {
|
||||
mutate: vi.fn(),
|
||||
},
|
||||
updatePreference: {
|
||||
mutate: vi.fn(),
|
||||
},
|
||||
updateGuide: {
|
||||
mutate: vi.fn(),
|
||||
},
|
||||
updateSettings: {
|
||||
mutate: vi.fn(),
|
||||
},
|
||||
resetSettings: {
|
||||
mutate: vi.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe('ServerService', () => {
|
||||
const service = new ServerService();
|
||||
|
||||
it('should get user registration duration', async () => {
|
||||
const mockData = {
|
||||
createdAt: '2023-01-01',
|
||||
duration: 100,
|
||||
updatedAt: '2023-01-02',
|
||||
};
|
||||
vi.mocked(lambdaClient.user.getUserRegistrationDuration.query).mockResolvedValue(mockData);
|
||||
|
||||
const result = await service.getUserRegistrationDuration();
|
||||
expect(result).toEqual(mockData);
|
||||
});
|
||||
|
||||
it('should get user state', async () => {
|
||||
const mockState: UserInitializationState = {
|
||||
isOnboard: true,
|
||||
preference: {
|
||||
telemetry: true,
|
||||
},
|
||||
settings: {},
|
||||
};
|
||||
vi.mocked(lambdaClient.user.getUserState.query).mockResolvedValue(mockState);
|
||||
|
||||
const result = await service.getUserState();
|
||||
expect(result).toEqual(mockState);
|
||||
});
|
||||
|
||||
it('should get user SSO providers', async () => {
|
||||
const mockProviders = [
|
||||
{
|
||||
provider: 'google',
|
||||
providerAccountId: '123',
|
||||
userId: 'user1',
|
||||
type: 'oauth' as const,
|
||||
access_token: 'token',
|
||||
token_type: 'bearer' as const,
|
||||
expires_at: 123,
|
||||
scope: 'email profile',
|
||||
},
|
||||
];
|
||||
vi.mocked(lambdaClient.user.getUserSSOProviders.query).mockResolvedValue(mockProviders);
|
||||
|
||||
const result = await service.getUserSSOProviders();
|
||||
expect(result).toEqual(mockProviders);
|
||||
});
|
||||
|
||||
it('should unlink SSO provider', async () => {
|
||||
const provider = 'google';
|
||||
const providerAccountId = '123';
|
||||
await service.unlinkSSOProvider(provider, providerAccountId);
|
||||
|
||||
expect(lambdaClient.user.unlinkSSOProvider.mutate).toHaveBeenCalledWith({
|
||||
provider,
|
||||
providerAccountId,
|
||||
});
|
||||
});
|
||||
|
||||
it('should make user onboarded', async () => {
|
||||
await service.makeUserOnboarded();
|
||||
expect(lambdaClient.user.makeUserOnboarded.mutate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update user preference', async () => {
|
||||
const preference: Partial<UserPreference> = {
|
||||
telemetry: true,
|
||||
useCmdEnterToSend: true,
|
||||
};
|
||||
await service.updatePreference(preference);
|
||||
expect(lambdaClient.user.updatePreference.mutate).toHaveBeenCalledWith(preference);
|
||||
});
|
||||
|
||||
it('should update user guide', async () => {
|
||||
const guide = {
|
||||
moveSettingsToAvatar: true,
|
||||
topic: false,
|
||||
uploadFileInKnowledgeBase: true,
|
||||
};
|
||||
await service.updateGuide(guide);
|
||||
expect(lambdaClient.user.updateGuide.mutate).toHaveBeenCalledWith(guide);
|
||||
});
|
||||
|
||||
it('should update user settings', async () => {
|
||||
const settings: PartialDeep<UserSettings> = {
|
||||
defaultAgent: {
|
||||
config: {
|
||||
model: 'gpt-4',
|
||||
provider: 'openai',
|
||||
},
|
||||
meta: {
|
||||
avatar: 'avatar',
|
||||
description: 'test agent',
|
||||
},
|
||||
},
|
||||
};
|
||||
const signal = new AbortController().signal;
|
||||
await service.updateUserSettings(settings, signal);
|
||||
expect(lambdaClient.user.updateSettings.mutate).toHaveBeenCalledWith(settings, { signal });
|
||||
});
|
||||
|
||||
it('should reset user settings', async () => {
|
||||
await service.resetUserSettings();
|
||||
expect(lambdaClient.user.resetSettings.mutate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { IUserService } from '@/services/user/type';
|
||||
|
||||
export class ServerService implements IUserService {
|
||||
getUserRegistrationDuration: IUserService['getUserRegistrationDuration'] = async () => {
|
||||
return lambdaClient.user.getUserRegistrationDuration.query();
|
||||
};
|
||||
|
||||
getUserState: IUserService['getUserState'] = async () => {
|
||||
return lambdaClient.user.getUserState.query();
|
||||
};
|
||||
|
||||
getUserSSOProviders: IUserService['getUserSSOProviders'] = async () => {
|
||||
return lambdaClient.user.getUserSSOProviders.query();
|
||||
};
|
||||
|
||||
unlinkSSOProvider: IUserService['unlinkSSOProvider'] = async (
|
||||
provider: string,
|
||||
providerAccountId: string,
|
||||
) => {
|
||||
return lambdaClient.user.unlinkSSOProvider.mutate({ provider, providerAccountId });
|
||||
};
|
||||
|
||||
makeUserOnboarded = async () => {
|
||||
return lambdaClient.user.makeUserOnboarded.mutate();
|
||||
};
|
||||
|
||||
updateAvatar: IUserService['updateAvatar'] = async (avatar) => {
|
||||
return lambdaClient.user.updateAvatar.mutate(avatar);
|
||||
};
|
||||
|
||||
updatePreference: IUserService['updatePreference'] = async (preference) => {
|
||||
return lambdaClient.user.updatePreference.mutate(preference);
|
||||
};
|
||||
|
||||
updateGuide: IUserService['updateGuide'] = async (guide) => {
|
||||
return lambdaClient.user.updateGuide.mutate(guide);
|
||||
};
|
||||
|
||||
updateUserSettings: IUserService['updateUserSettings'] = async (value, signal) => {
|
||||
return lambdaClient.user.updateSettings.mutate(value, { signal });
|
||||
};
|
||||
|
||||
resetUserSettings: IUserService['resetUserSettings'] = async () => {
|
||||
return lambdaClient.user.resetSettings.mutate();
|
||||
};
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import type { AdapterAccount } from 'next-auth/adapters';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
|
||||
import { UserGuide, UserInitializationState, UserPreference } from '@/types/user';
|
||||
import { UserSettings } from '@/types/user/settings';
|
||||
|
||||
export interface IUserService {
|
||||
getUserRegistrationDuration: () => Promise<{
|
||||
createdAt: string;
|
||||
duration: number;
|
||||
updatedAt: string;
|
||||
}>;
|
||||
getUserSSOProviders: () => Promise<AdapterAccount[]>;
|
||||
getUserState: () => Promise<UserInitializationState>;
|
||||
resetUserSettings: () => Promise<any>;
|
||||
unlinkSSOProvider: (provider: string, providerAccountId: string) => Promise<any>;
|
||||
updateAvatar: (avatar: string) => Promise<any>;
|
||||
updateGuide: (guide: Partial<UserGuide>) => Promise<any>;
|
||||
updatePreference: (preference: Partial<UserPreference>) => Promise<any>;
|
||||
updateUserSettings: (value: PartialDeep<UserSettings>, signal?: AbortSignal) => Promise<any>;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ describe('AiModelAction', () => {
|
||||
.mockResolvedValue(undefined);
|
||||
const serviceSpy = vi
|
||||
.spyOn(aiModelService, 'batchUpdateAiModels')
|
||||
.mockResolvedValue(undefined);
|
||||
.mockResolvedValue(undefined as any);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.batchUpdateAiModels(models);
|
||||
@@ -119,7 +119,7 @@ describe('AiModelAction', () => {
|
||||
const { result } = renderHook(() => useStore());
|
||||
const serviceSpy = vi
|
||||
.spyOn(aiModelService, 'batchUpdateAiModels')
|
||||
.mockResolvedValue(undefined);
|
||||
.mockResolvedValue(undefined as any);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.batchUpdateAiModels([]);
|
||||
@@ -137,7 +137,7 @@ describe('AiModelAction', () => {
|
||||
.mockResolvedValue(undefined);
|
||||
const serviceSpy = vi
|
||||
.spyOn(aiModelService, 'clearModelsByProvider')
|
||||
.mockResolvedValue(undefined);
|
||||
.mockResolvedValue(undefined as any);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.clearModelsByProvider('test-provider');
|
||||
@@ -154,7 +154,9 @@ describe('AiModelAction', () => {
|
||||
const refreshSpy = vi
|
||||
.spyOn(result.current, 'refreshAiModelList')
|
||||
.mockResolvedValue(undefined);
|
||||
const serviceSpy = vi.spyOn(aiModelService, 'clearRemoteModels').mockResolvedValue(undefined);
|
||||
const serviceSpy = vi
|
||||
.spyOn(aiModelService, 'clearRemoteModels')
|
||||
.mockResolvedValue(undefined as any);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.clearRemoteModels('test-provider');
|
||||
@@ -178,7 +180,9 @@ describe('AiModelAction', () => {
|
||||
const refreshSpy = vi
|
||||
.spyOn(result.current, 'refreshAiModelList')
|
||||
.mockResolvedValue(undefined);
|
||||
const serviceSpy = vi.spyOn(aiModelService, 'createAiModel').mockResolvedValue(undefined);
|
||||
const serviceSpy = vi
|
||||
.spyOn(aiModelService, 'createAiModel')
|
||||
.mockResolvedValue(undefined as any);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.createNewAiModel(params);
|
||||
@@ -349,7 +353,9 @@ describe('AiModelAction', () => {
|
||||
const refreshSpy = vi
|
||||
.spyOn(result.current, 'refreshAiModelList')
|
||||
.mockResolvedValue(undefined);
|
||||
const serviceSpy = vi.spyOn(aiModelService, 'deleteAiModel').mockResolvedValue(undefined);
|
||||
const serviceSpy = vi
|
||||
.spyOn(aiModelService, 'deleteAiModel')
|
||||
.mockResolvedValue(undefined as any);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.removeAiModel('model-1', 'test-provider');
|
||||
@@ -371,7 +377,7 @@ describe('AiModelAction', () => {
|
||||
.mockResolvedValue(undefined);
|
||||
const serviceSpy = vi
|
||||
.spyOn(aiModelService, 'toggleModelEnabled')
|
||||
.mockResolvedValue(undefined);
|
||||
.mockResolvedValue(undefined as any);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.toggleModelEnabled({ enabled: true, id: 'model-1' });
|
||||
@@ -395,7 +401,7 @@ describe('AiModelAction', () => {
|
||||
const { result } = renderHook(() => useStore());
|
||||
const serviceSpy = vi
|
||||
.spyOn(aiModelService, 'toggleModelEnabled')
|
||||
.mockResolvedValue(undefined);
|
||||
.mockResolvedValue(undefined as any);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.toggleModelEnabled({ enabled: true, id: 'model-1' });
|
||||
@@ -435,7 +441,9 @@ describe('AiModelAction', () => {
|
||||
const refreshSpy = vi
|
||||
.spyOn(result.current, 'refreshAiModelList')
|
||||
.mockResolvedValue(undefined);
|
||||
const serviceSpy = vi.spyOn(aiModelService, 'updateAiModel').mockResolvedValue(undefined);
|
||||
const serviceSpy = vi
|
||||
.spyOn(aiModelService, 'updateAiModel')
|
||||
.mockResolvedValue(undefined as any);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.updateAiModelsConfig('model-1', 'test-provider', updateData);
|
||||
|
||||
@@ -63,10 +63,12 @@ export const spyOnMessageService = () => {
|
||||
const updateMessageSpy = vi
|
||||
.spyOn(messageService, 'updateMessage')
|
||||
.mockResolvedValue({ messages: [], success: true });
|
||||
const removeMessageSpy = vi.spyOn(messageService, 'removeMessage').mockResolvedValue(undefined);
|
||||
const removeMessageSpy = vi
|
||||
.spyOn(messageService, 'removeMessage')
|
||||
.mockResolvedValue(undefined as any);
|
||||
const updateMessageErrorSpy = vi
|
||||
.spyOn(messageService, 'updateMessageError')
|
||||
.mockResolvedValue(undefined);
|
||||
.mockResolvedValue(undefined as any);
|
||||
|
||||
return {
|
||||
createMessageSpy,
|
||||
|
||||
@@ -254,7 +254,7 @@ describe('topic action', () => {
|
||||
|
||||
const updateFavoriteSpy = vi
|
||||
.spyOn(topicService, 'updateTopic')
|
||||
.mockResolvedValue({ success: 1 });
|
||||
.mockResolvedValue(undefined as any);
|
||||
|
||||
const refreshTopicSpy = vi.spyOn(result.current, 'refreshTopic');
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import { useClientDataSWR } from '@/libs/swr';
|
||||
import { chatService } from '@/services/chat';
|
||||
import { messageService } from '@/services/message';
|
||||
import { topicService } from '@/services/topic';
|
||||
import { CreateTopicParams } from '@/services/topic/type';
|
||||
import type { ChatStore } from '@/store/chat';
|
||||
import type { ChatStoreState } from '@/store/chat/initialState';
|
||||
import { messageMapKey } from '@/store/chat/utils/messageMapKey';
|
||||
@@ -24,7 +23,7 @@ import { useSessionStore } from '@/store/session';
|
||||
import { sessionSelectors } from '@/store/session/selectors';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { systemAgentSelectors } from '@/store/user/selectors';
|
||||
import { ChatTopic } from '@/types/topic';
|
||||
import { ChatTopic, CreateTopicParams } from '@/types/topic';
|
||||
import { merge } from '@/utils/merge';
|
||||
import { setNamespace } from '@/utils/storeDebug';
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { produce } from 'immer';
|
||||
|
||||
import { CreateTopicParams } from '@/services/topic/type';
|
||||
import { ChatTopic } from '@/types/topic';
|
||||
import { ChatTopic, CreateTopicParams } from '@/types/topic';
|
||||
|
||||
interface AddChatTopicAction {
|
||||
type: 'addTopic';
|
||||
|
||||
@@ -4,7 +4,6 @@ import { StateCreator } from 'zustand/vanilla';
|
||||
import { notification } from '@/components/AntdStaticMethods';
|
||||
import { FILE_UPLOAD_BLACKLIST } from '@/const/file';
|
||||
import { fileService } from '@/services/file';
|
||||
import { ServerService } from '@/services/file/server';
|
||||
import { ragService } from '@/services/rag';
|
||||
import { UPLOAD_NETWORK_ERROR } from '@/services/upload';
|
||||
import {
|
||||
@@ -21,8 +20,6 @@ import { FileStore } from '../../store';
|
||||
|
||||
const n = setNamespace('chat');
|
||||
|
||||
const serverFileService = new ServerService();
|
||||
|
||||
export interface FileAction {
|
||||
clearChatUploadFileList: () => void;
|
||||
dispatchChatUploadFileList: (payload: UploadFileListDispatch) => void;
|
||||
@@ -71,7 +68,7 @@ export const createFileSlice: StateCreator<
|
||||
let fileItem: FileListItem | undefined = undefined;
|
||||
|
||||
try {
|
||||
fileItem = await serverFileService.getFileItem(id);
|
||||
fileItem = await fileService.getFileItem(id);
|
||||
} catch (e) {
|
||||
console.error('getFileItem Error:', e);
|
||||
continue;
|
||||
|
||||
@@ -4,8 +4,7 @@ import { StateCreator } from 'zustand/vanilla';
|
||||
|
||||
import { FILE_UPLOAD_BLACKLIST, MAX_UPLOAD_FILE_COUNT } from '@/const/file';
|
||||
import { useClientDataSWR } from '@/libs/swr';
|
||||
import { fileService } from '@/services/file';
|
||||
import { ServerService } from '@/services/file/server';
|
||||
import { fileService , FileService } from '@/services/file';
|
||||
import { ragService } from '@/services/rag';
|
||||
import {
|
||||
UploadFileListDispatch,
|
||||
@@ -18,7 +17,7 @@ import { unzipFile } from '@/utils/unzipFile';
|
||||
import { FileStore } from '../../store';
|
||||
import { fileManagerSelectors } from './selectors';
|
||||
|
||||
const serverFileService = new ServerService();
|
||||
const serverFileService = new FileService();
|
||||
|
||||
export interface FileManageAction {
|
||||
dispatchDockFileList: (payload: UploadFileListDispatch) => void;
|
||||
|
||||
@@ -42,7 +42,7 @@ describe('createSessionGroupSlice', () => {
|
||||
it('should clear session groups and refresh sessions', async () => {
|
||||
const spyOn = vi
|
||||
.spyOn(sessionService, 'removeSessionGroups')
|
||||
.mockResolvedValueOnce(undefined);
|
||||
.mockResolvedValueOnce(undefined as any);
|
||||
const spyOnRefreshSessions = vi.spyOn(useSessionStore.getState(), 'refreshSessions');
|
||||
|
||||
const { result } = renderHook(() => useSessionStore());
|
||||
@@ -59,7 +59,7 @@ describe('createSessionGroupSlice', () => {
|
||||
describe('removeSessionGroup', () => {
|
||||
it('should remove a session group and refresh sessions', async () => {
|
||||
const mockId = 'mock-id';
|
||||
vi.spyOn(sessionService, 'removeSessionGroup').mockResolvedValueOnce(undefined);
|
||||
vi.spyOn(sessionService, 'removeSessionGroup').mockResolvedValueOnce(undefined as any);
|
||||
const spyOnRefreshSessions = vi.spyOn(useSessionStore.getState(), 'refreshSessions');
|
||||
|
||||
const { result } = renderHook(() => useSessionStore());
|
||||
@@ -77,7 +77,7 @@ describe('createSessionGroupSlice', () => {
|
||||
it('should update a session group id and refresh sessions', async () => {
|
||||
const mockSessionId = 'session-id';
|
||||
const mockGroupId = 'group-id';
|
||||
vi.spyOn(sessionService, 'updateSession').mockResolvedValueOnce(undefined);
|
||||
vi.spyOn(sessionService, 'updateSession').mockResolvedValueOnce(undefined as any);
|
||||
const spyOnRefreshSessions = vi.spyOn(useSessionStore.getState(), 'refreshSessions');
|
||||
|
||||
const { result } = renderHook(() => useSessionStore());
|
||||
@@ -98,7 +98,7 @@ describe('createSessionGroupSlice', () => {
|
||||
const mockId = 'mock-id';
|
||||
const mockName = 'New Name';
|
||||
const spyOnRefreshSessions = vi.spyOn(useSessionStore.getState(), 'refreshSessions');
|
||||
vi.spyOn(sessionService, 'updateSessionGroup').mockResolvedValueOnce(undefined);
|
||||
vi.spyOn(sessionService, 'updateSessionGroup').mockResolvedValueOnce(undefined as any);
|
||||
|
||||
const { result } = renderHook(() => useSessionStore());
|
||||
|
||||
@@ -117,7 +117,7 @@ describe('createSessionGroupSlice', () => {
|
||||
{ id: 'id1', sort: 0 },
|
||||
{ id: 'id2', sort: 1 },
|
||||
];
|
||||
vi.spyOn(sessionService, 'updateSessionGroupOrder').mockResolvedValueOnce(undefined);
|
||||
vi.spyOn(sessionService, 'updateSessionGroupOrder').mockResolvedValueOnce(undefined as any);
|
||||
const spyOnRefreshSessions = vi.spyOn(useSessionStore.getState(), 'refreshSessions');
|
||||
|
||||
const { result } = renderHook(() => useSessionStore());
|
||||
|
||||
@@ -30,7 +30,7 @@ describe('createCommonSlice', () => {
|
||||
const avatar = 'data:image/png;base64,';
|
||||
|
||||
const spyOn = vi.spyOn(result.current, 'refreshUserState');
|
||||
const updateAvatarSpy = vi.spyOn(userService, 'updateAvatar').mockResolvedValue(undefined);
|
||||
const updateAvatarSpy = vi.spyOn(userService, 'updateAvatar').mockResolvedValue({} as any);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.updateAvatar(avatar);
|
||||
|
||||
Reference in New Issue
Block a user