mirror of
https://github.com/docmost/docmost.git
synced 2026-05-08 23:33:09 +08:00
feat: ai chat
This commit is contained in:
@@ -46,6 +46,10 @@ export class UpdateWorkspaceDto extends PartialType(CreateWorkspaceDto) {
|
||||
@IsBoolean()
|
||||
mcpEnabled: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
aiChat: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
|
||||
@@ -440,11 +440,26 @@ export class WorkspaceService {
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof updateWorkspaceDto.aiChat !== 'undefined') {
|
||||
const prev = settingsBefore?.ai?.chat ?? false;
|
||||
if (prev !== updateWorkspaceDto.aiChat) {
|
||||
before.aiChat = prev;
|
||||
after.aiChat = updateWorkspaceDto.aiChat;
|
||||
}
|
||||
await this.workspaceRepo.updateAiSettings(
|
||||
workspaceId,
|
||||
'chat',
|
||||
updateWorkspaceDto.aiChat,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
delete updateWorkspaceDto.restrictApiToAdmins;
|
||||
delete updateWorkspaceDto.aiSearch;
|
||||
delete updateWorkspaceDto.generativeAi;
|
||||
delete updateWorkspaceDto.disablePublicSharing;
|
||||
delete updateWorkspaceDto.mcpEnabled;
|
||||
delete updateWorkspaceDto.aiChat;
|
||||
|
||||
await this.workspaceRepo.updateWorkspace(
|
||||
updateWorkspaceDto,
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { type Kysely, sql } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
.createTable('ai_chats')
|
||||
.addColumn('id', 'uuid', (col) =>
|
||||
col.primaryKey().defaultTo(sql`gen_uuid_v7()`),
|
||||
)
|
||||
.addColumn('workspace_id', 'uuid', (col) =>
|
||||
col.references('workspaces.id').onDelete('cascade').notNull(),
|
||||
)
|
||||
.addColumn('creator_id', 'uuid', (col) =>
|
||||
col.references('users.id').notNull(),
|
||||
)
|
||||
.addColumn('title', 'varchar', (col) => col)
|
||||
.addColumn('created_at', 'timestamptz', (col) =>
|
||||
col.notNull().defaultTo(sql`now()`),
|
||||
)
|
||||
.addColumn('updated_at', 'timestamptz', (col) =>
|
||||
col.notNull().defaultTo(sql`now()`),
|
||||
)
|
||||
.execute();
|
||||
|
||||
await db.schema
|
||||
.createIndex('idx_ai_chats_workspace_creator')
|
||||
.on('ai_chats')
|
||||
.columns(['workspace_id', 'creator_id', 'id'])
|
||||
.execute();
|
||||
|
||||
await db.schema
|
||||
.createTable('ai_chat_messages')
|
||||
.addColumn('id', 'uuid', (col) =>
|
||||
col.primaryKey().defaultTo(sql`gen_uuid_v7()`),
|
||||
)
|
||||
.addColumn('chat_id', 'uuid', (col) =>
|
||||
col.references('ai_chats.id').onDelete('cascade').notNull(),
|
||||
)
|
||||
.addColumn('workspace_id', 'uuid', (col) =>
|
||||
col.references('workspaces.id').onDelete('cascade').notNull(),
|
||||
)
|
||||
.addColumn('role', 'varchar', (col) => col.notNull())
|
||||
.addColumn('content', 'text', (col) => col)
|
||||
.addColumn('tool_calls', 'jsonb', (col) => col)
|
||||
.addColumn('metadata', 'jsonb', (col) => col)
|
||||
.addColumn('created_at', 'timestamptz', (col) =>
|
||||
col.notNull().defaultTo(sql`now()`),
|
||||
)
|
||||
.execute();
|
||||
|
||||
await db.schema
|
||||
.createIndex('idx_ai_chat_messages_chat_id')
|
||||
.on('ai_chat_messages')
|
||||
.columns(['chat_id', 'id'])
|
||||
.execute();
|
||||
}
|
||||
|
||||
export async function down(db: Kysely<any>): Promise<void> {
|
||||
await db.schema.dropTable('ai_chat_messages').execute();
|
||||
await db.schema.dropTable('ai_chats').execute();
|
||||
}
|
||||
@@ -44,6 +44,21 @@ export class AttachmentRepo {
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
async findByIdWithContent(
|
||||
attachmentId: string,
|
||||
opts?: {
|
||||
trx?: KyselyTransaction;
|
||||
},
|
||||
): Promise<Attachment> {
|
||||
const db = dbOrTx(this.db, opts?.trx);
|
||||
|
||||
return db
|
||||
.selectFrom('attachments')
|
||||
.select([...this.baseFields, 'textContent'])
|
||||
.where('id', '=', attachmentId)
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
async insertAttachment(
|
||||
insertableAttachment: InsertableAttachment,
|
||||
trx?: KyselyTransaction,
|
||||
|
||||
+22
@@ -429,7 +429,29 @@ export interface PagePermissions {
|
||||
updatedAt: Generated<Timestamp>;
|
||||
}
|
||||
|
||||
export interface AiChats {
|
||||
id: Generated<string>;
|
||||
workspaceId: string;
|
||||
creatorId: string;
|
||||
title: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
}
|
||||
|
||||
export interface AiChatMessages {
|
||||
id: Generated<string>;
|
||||
chatId: string;
|
||||
workspaceId: string;
|
||||
role: string;
|
||||
content: string | null;
|
||||
toolCalls: Json | null;
|
||||
metadata: Json | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
}
|
||||
|
||||
export interface DB {
|
||||
aiChats: AiChats;
|
||||
aiChatMessages: AiChatMessages;
|
||||
apiKeys: ApiKeys;
|
||||
attachments: Attachments;
|
||||
audit: Audit;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Insertable, Selectable, Updateable } from 'kysely';
|
||||
import {
|
||||
AiChats,
|
||||
AiChatMessages,
|
||||
Attachments,
|
||||
Comments,
|
||||
Groups,
|
||||
@@ -28,6 +30,15 @@ import {
|
||||
} from './db';
|
||||
import { PageEmbeddings } from '@docmost/db/types/embeddings.types';
|
||||
|
||||
// AI Chat
|
||||
export type AiChat = Selectable<AiChats>;
|
||||
export type InsertableAiChat = Insertable<AiChats>;
|
||||
export type UpdatableAiChat = Updateable<Omit<AiChats, 'id'>>;
|
||||
|
||||
// AI Chat Message
|
||||
export type AiChatMessage = Selectable<AiChatMessages>;
|
||||
export type InsertableAiChatMessage = Insertable<AiChatMessages>;
|
||||
|
||||
// Workspace
|
||||
export type Workspace = Selectable<Workspaces>;
|
||||
export type InsertableWorkspace = Insertable<Workspaces>;
|
||||
|
||||
+1
-1
Submodule apps/server/src/ee updated: 8b7ae8cf1b...8b48e93a1b
@@ -252,6 +252,13 @@ export class EnvironmentService {
|
||||
return this.configService.get<string>('AI_COMPLETION_MODEL');
|
||||
}
|
||||
|
||||
getAiChatModel(): string {
|
||||
return (
|
||||
this.configService.get<string>('AI_CHAT_MODEL') ||
|
||||
this.configService.get<string>('AI_COMPLETION_MODEL')
|
||||
);
|
||||
}
|
||||
|
||||
getAiEmbeddingDimension(): number {
|
||||
return parseInt(
|
||||
this.configService.get<string>('AI_EMBEDDING_DIMENSION'),
|
||||
|
||||
Reference in New Issue
Block a user