feat(admin): LLM config, knowledge base, and WeCom AI binding
CI / verify (pull_request) Has been cancelled
CI / verify (pull_request) Has been cancelled
Add owner-scoped model API settings, uploadable knowledge bases, and WeCom bot AI/KB wiring with OpenAI-compatible URL normalization. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
|
||||
const p = new PrismaClient();
|
||||
|
||||
async function ensureColumn(table, column, ddl) {
|
||||
const cols = await p.$queryRawUnsafe(`SHOW COLUMNS FROM \`${table}\` LIKE '${column}'`);
|
||||
if (!cols.length) {
|
||||
await p.$executeRawUnsafe(ddl);
|
||||
console.log(`added ${table}.${column}`);
|
||||
} else {
|
||||
console.log(`${table}.${column} exists`);
|
||||
}
|
||||
}
|
||||
|
||||
(async () => {
|
||||
await ensureColumn(
|
||||
'wecom_bot',
|
||||
'ai_enabled',
|
||||
'ALTER TABLE `wecom_bot` ADD COLUMN `ai_enabled` TINYINT(1) NOT NULL DEFAULT 0 AFTER `permissions`',
|
||||
);
|
||||
await ensureColumn(
|
||||
'wecom_bot',
|
||||
'llm_config_id',
|
||||
'ALTER TABLE `wecom_bot` ADD COLUMN `llm_config_id` BIGINT UNSIGNED NULL AFTER `ai_enabled`',
|
||||
);
|
||||
await ensureColumn(
|
||||
'wecom_bot',
|
||||
'knowledge_base_id',
|
||||
'ALTER TABLE `wecom_bot` ADD COLUMN `knowledge_base_id` BIGINT UNSIGNED NULL AFTER `llm_config_id`',
|
||||
);
|
||||
await p.$disconnect();
|
||||
})().catch(async (e) => {
|
||||
console.error(e);
|
||||
await p.$disconnect();
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
-- LLM / 知识库 / 企微 AI 字段
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `llm_api_config` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(64) NOT NULL,
|
||||
`provider` VARCHAR(32) NOT NULL,
|
||||
`base_url` VARCHAR(512) NOT NULL,
|
||||
`api_key` VARCHAR(512) NOT NULL,
|
||||
`model_name` VARCHAR(128) NOT NULL,
|
||||
`temperature` DECIMAL(3, 2) NULL,
|
||||
`max_tokens` INT NULL,
|
||||
`system_prompt` TEXT NULL,
|
||||
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_by_hq_account_id` BIGINT UNSIGNED NOT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `llm_api_config_created_by_hq_account_id_enabled_idx` (`created_by_hq_account_id`, `enabled`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `knowledge_base` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(128) NOT NULL,
|
||||
`description` VARCHAR(512) NULL,
|
||||
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_by_hq_account_id` BIGINT UNSIGNED NOT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `knowledge_base_created_by_hq_account_id_enabled_idx` (`created_by_hq_account_id`, `enabled`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `knowledge_document` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`knowledge_base_id` BIGINT UNSIGNED NOT NULL,
|
||||
`title` VARCHAR(256) NOT NULL,
|
||||
`file_name` VARCHAR(256) NULL,
|
||||
`file_url` VARCHAR(1024) NULL,
|
||||
`mime_type` VARCHAR(128) NULL,
|
||||
`size_bytes` INT NULL,
|
||||
`content_text` LONGTEXT NULL,
|
||||
`status` VARCHAR(16) NOT NULL DEFAULT 'READY',
|
||||
`error_message` VARCHAR(512) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `knowledge_document_knowledge_base_id_idx` (`knowledge_base_id`),
|
||||
CONSTRAINT `knowledge_document_knowledge_base_id_fkey`
|
||||
FOREIGN KEY (`knowledge_base_id`) REFERENCES `knowledge_base` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -352,24 +352,92 @@ model SystemConfig {
|
||||
|
||||
/// 企业微信智能机器人(HQ 可创建多实例,长连接)
|
||||
model WecomBot {
|
||||
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
|
||||
name String @db.VarChar(64)
|
||||
role String @db.VarChar(32)
|
||||
botId String @unique @map("bot_id") @db.VarChar(128)
|
||||
secret String @db.VarChar(256)
|
||||
avatarUrl String? @map("avatar_url") @db.VarChar(512)
|
||||
welcome String? @db.VarChar(1024)
|
||||
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
|
||||
name String @db.VarChar(64)
|
||||
role String @db.VarChar(32)
|
||||
botId String @unique @map("bot_id") @db.VarChar(128)
|
||||
secret String @db.VarChar(256)
|
||||
avatarUrl String? @map("avatar_url") @db.VarChar(512)
|
||||
welcome String? @db.VarChar(1024)
|
||||
/// JSON 字符串数组,如 ["ticket.create","user.view_sms"]
|
||||
permissions String @db.Text
|
||||
enabled Boolean @default(true)
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
|
||||
permissions String @db.Text
|
||||
/// 未匹配指令时是否调用语言模型
|
||||
aiEnabled Boolean @default(false) @map("ai_enabled")
|
||||
llmConfigId BigInt? @map("llm_config_id") @db.UnsignedBigInt
|
||||
knowledgeBaseId BigInt? @map("knowledge_base_id") @db.UnsignedBigInt
|
||||
enabled Boolean @default(true)
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
|
||||
|
||||
llmConfig LlmApiConfig? @relation(fields: [llmConfigId], references: [id], onDelete: SetNull)
|
||||
knowledgeBase KnowledgeBase? @relation(fields: [knowledgeBaseId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@index([enabled, sortOrder])
|
||||
@@index([llmConfigId])
|
||||
@@index([knowledgeBaseId])
|
||||
@@map("wecom_bot")
|
||||
}
|
||||
|
||||
/// HQ 语言模型 API 配置(非超管仅可见/可开关自己创建的)
|
||||
model LlmApiConfig {
|
||||
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
|
||||
name String @db.VarChar(64)
|
||||
provider String @db.VarChar(32)
|
||||
baseUrl String @map("base_url") @db.VarChar(512)
|
||||
apiKey String @map("api_key") @db.VarChar(512)
|
||||
modelName String @map("model_name") @db.VarChar(128)
|
||||
temperature Decimal? @db.Decimal(3, 2)
|
||||
maxTokens Int? @map("max_tokens")
|
||||
systemPrompt String? @map("system_prompt") @db.Text
|
||||
enabled Boolean @default(true)
|
||||
createdByHqAccountId BigInt @map("created_by_hq_account_id") @db.UnsignedBigInt
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
|
||||
|
||||
wecomBots WecomBot[]
|
||||
|
||||
@@index([createdByHqAccountId, enabled])
|
||||
@@map("llm_api_config")
|
||||
}
|
||||
|
||||
/// HQ 知识库
|
||||
model KnowledgeBase {
|
||||
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
|
||||
name String @db.VarChar(128)
|
||||
description String? @db.VarChar(512)
|
||||
enabled Boolean @default(true)
|
||||
createdByHqAccountId BigInt @map("created_by_hq_account_id") @db.UnsignedBigInt
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
|
||||
|
||||
documents KnowledgeDocument[]
|
||||
wecomBots WecomBot[]
|
||||
|
||||
@@index([createdByHqAccountId, enabled])
|
||||
@@map("knowledge_base")
|
||||
}
|
||||
|
||||
model KnowledgeDocument {
|
||||
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
|
||||
knowledgeBaseId BigInt @map("knowledge_base_id") @db.UnsignedBigInt
|
||||
title String @db.VarChar(256)
|
||||
fileName String? @map("file_name") @db.VarChar(256)
|
||||
fileUrl String? @map("file_url") @db.VarChar(1024)
|
||||
mimeType String? @map("mime_type") @db.VarChar(128)
|
||||
sizeBytes Int? @map("size_bytes")
|
||||
contentText String? @map("content_text") @db.LongText
|
||||
status String @default("READY") @db.VarChar(16)
|
||||
errorMessage String? @map("error_message") @db.VarChar(512)
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
|
||||
|
||||
knowledgeBase KnowledgeBase @relation(fields: [knowledgeBaseId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([knowledgeBaseId])
|
||||
@@map("knowledge_document")
|
||||
}
|
||||
|
||||
model MockSmsCode {
|
||||
id BigInt @id @default(autoincrement()) @db.UnsignedBigInt
|
||||
phone String @db.VarChar(20)
|
||||
|
||||
Reference in New Issue
Block a user