@lobehub/chat
Version:
Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.
160 lines (137 loc) • 4.5 kB
text/typescript
import { and, desc, eq, inArray } from 'drizzle-orm/expressions';
import {
agents,
agentsFiles,
agentsKnowledgeBases,
agentsToSessions,
files,
knowledgeBases,
} from '@/database/schemas';
import { LobeChatDatabase } from '@/database/type';
export class AgentModel {
private userId: string;
private db: LobeChatDatabase;
constructor(db: LobeChatDatabase, userId: string) {
this.userId = userId;
this.db = db;
}
getAgentConfigById = async (id: string) => {
const agent = await this.db.query.agents.findFirst({ where: eq(agents.id, id) });
const knowledge = await this.getAgentAssignedKnowledge(id);
return { ...agent, ...knowledge };
};
getAgentAssignedKnowledge = async (id: string) => {
const knowledgeBaseResult = await this.db
.select({ enabled: agentsKnowledgeBases.enabled, knowledgeBases })
.from(agentsKnowledgeBases)
.where(eq(agentsKnowledgeBases.agentId, id))
.orderBy(desc(agentsKnowledgeBases.createdAt))
.leftJoin(knowledgeBases, eq(knowledgeBases.id, agentsKnowledgeBases.knowledgeBaseId));
const fileResult = await this.db
.select({ enabled: agentsFiles.enabled, files })
.from(agentsFiles)
.where(eq(agentsFiles.agentId, id))
.orderBy(desc(agentsFiles.createdAt))
.leftJoin(files, eq(files.id, agentsFiles.fileId));
return {
files: fileResult.map((item) => ({
...item.files,
enabled: item.enabled,
})),
knowledgeBases: knowledgeBaseResult.map((item) => ({
...item.knowledgeBases,
enabled: item.enabled,
})),
};
};
/**
* Find agent by session id
*/
findBySessionId = async (sessionId: string) => {
const item = await this.db.query.agentsToSessions.findFirst({
where: eq(agentsToSessions.sessionId, sessionId),
});
if (!item) return;
const agentId = item.agentId;
return this.getAgentConfigById(agentId);
};
createAgentKnowledgeBase = async (
agentId: string,
knowledgeBaseId: string,
enabled: boolean = true,
) => {
return this.db.insert(agentsKnowledgeBases).values({
agentId,
enabled,
knowledgeBaseId,
userId: this.userId,
});
};
deleteAgentKnowledgeBase = async (agentId: string, knowledgeBaseId: string) => {
return this.db
.delete(agentsKnowledgeBases)
.where(
and(
eq(agentsKnowledgeBases.agentId, agentId),
eq(agentsKnowledgeBases.knowledgeBaseId, knowledgeBaseId),
eq(agentsKnowledgeBases.userId, this.userId),
),
);
};
toggleKnowledgeBase = async (agentId: string, knowledgeBaseId: string, enabled?: boolean) => {
return this.db
.update(agentsKnowledgeBases)
.set({ enabled })
.where(
and(
eq(agentsKnowledgeBases.agentId, agentId),
eq(agentsKnowledgeBases.knowledgeBaseId, knowledgeBaseId),
eq(agentsKnowledgeBases.userId, this.userId),
),
);
};
createAgentFiles = async (agentId: string, fileIds: string[], enabled: boolean = true) => {
// Exclude the fileIds that already exist in agentsFiles, and then insert them
const existingFiles = await this.db
.select({ id: agentsFiles.fileId })
.from(agentsFiles)
.where(
and(
eq(agentsFiles.agentId, agentId),
eq(agentsFiles.userId, this.userId),
inArray(agentsFiles.fileId, fileIds),
),
);
const existingFilesIds = new Set(existingFiles.map((item) => item.id));
const needToInsertFileIds = fileIds.filter((fileId) => !existingFilesIds.has(fileId));
if (needToInsertFileIds.length === 0) return;
return this.db
.insert(agentsFiles)
.values(
needToInsertFileIds.map((fileId) => ({ agentId, enabled, fileId, userId: this.userId })),
);
};
deleteAgentFile = async (agentId: string, fileId: string) => {
return this.db
.delete(agentsFiles)
.where(
and(
eq(agentsFiles.agentId, agentId),
eq(agentsFiles.fileId, fileId),
eq(agentsFiles.userId, this.userId),
),
);
};
toggleFile = async (agentId: string, fileId: string, enabled?: boolean) => {
return this.db
.update(agentsFiles)
.set({ enabled })
.where(
and(
eq(agentsFiles.agentId, agentId),
eq(agentsFiles.fileId, fileId),
eq(agentsFiles.userId, this.userId),
),
);
};
}