feat: update ai integration (#2422)
* init Signed-off-by: Innei <tukon479@gmail.com> * update Signed-off-by: Innei <tukon479@gmail.com> * chore: update package dependencies and remove unused code - Updated package manager version in package.json to pnpm@10.10.0. - Removed references to `@modelcontextprotocol/sdk` from core application files. - Deleted unused `mcp.controller.ts` and cleaned up related imports in `mcp.module.ts`. - Adjusted optional dependencies in pnpm-lock.yaml. Signed-off-by: Innei <tukon479@gmail.com> * refactor: update AI summary and writer services to use new tools parser - Replaced `JsonOutputFunctionsParser` with `JsonOutputToolsParser` in both `ai-summary.service.ts` and `ai-writer.service.ts`. - Updated function definitions to align with the new tools structure, including changes to how functions are defined and invoked. - Enhanced error handling to return empty objects when no results are found. Signed-off-by: Innei <tukon479@gmail.com> --------- Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
@@ -52,121 +52,121 @@
|
|||||||
"redis-memory-server": "^0.12.1"
|
"redis-memory-server": "^0.12.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@algolia/client-search": "^4.22.1",
|
"@algolia/client-search": "catalog:",
|
||||||
"@antfu/install-pkg": "1.0.0",
|
"@antfu/install-pkg": "catalog:",
|
||||||
"@aws-sdk/client-s3": "3.802.0",
|
"@aws-sdk/client-s3": "catalog:",
|
||||||
"@babel/core": "7.27.1",
|
"@babel/core": "catalog:",
|
||||||
"@babel/plugin-transform-modules-commonjs": "7.27.1",
|
"@babel/plugin-transform-modules-commonjs": "catalog:",
|
||||||
"@babel/plugin-transform-typescript": "7.27.1",
|
"@babel/plugin-transform-typescript": "catalog:",
|
||||||
"@babel/types": "^7.27.1",
|
"@babel/types": "catalog:",
|
||||||
"@fastify/cookie": "11.0.2",
|
"@fastify/cookie": "catalog:",
|
||||||
"@fastify/multipart": "9.0.3",
|
"@fastify/multipart": "catalog:",
|
||||||
"@fastify/static": "8.1.1",
|
"@fastify/static": "catalog:",
|
||||||
"@innei/next-async": "0.3.0",
|
"@innei/next-async": "catalog:",
|
||||||
"@innei/pretty-logger-nestjs": "0.3.3",
|
"@innei/pretty-logger-nestjs": "catalog:",
|
||||||
"@keyv/redis": "4.4.0",
|
"@keyv/redis": "catalog:",
|
||||||
"@langchain/openai": "0.5.10",
|
"@langchain/openai": "catalog:",
|
||||||
"@mx-space/compiled": "workspace:*",
|
"@mx-space/compiled": "workspace:*",
|
||||||
"@nestjs/cache-manager": "3.0.1",
|
"@nestjs/cache-manager": "catalog:",
|
||||||
"@nestjs/common": "11.1.0",
|
"@nestjs/common": "catalog:",
|
||||||
"@nestjs/core": "11.1.0",
|
"@nestjs/core": "catalog:",
|
||||||
"@nestjs/event-emitter": "3.0.1",
|
"@nestjs/event-emitter": "catalog:",
|
||||||
"@nestjs/mapped-types": "^2.1.0",
|
"@nestjs/mapped-types": "catalog:",
|
||||||
"@nestjs/platform-fastify": "11.1.0",
|
"@nestjs/platform-fastify": "catalog:",
|
||||||
"@nestjs/platform-socket.io": "11.1.0",
|
"@nestjs/platform-socket.io": "catalog:",
|
||||||
"@nestjs/schedule": "6.0.0",
|
"@nestjs/schedule": "catalog:",
|
||||||
"@nestjs/throttler": "6.4.0",
|
"@nestjs/throttler": "catalog:",
|
||||||
"@nestjs/websockets": "11.1.0",
|
"@nestjs/websockets": "catalog:",
|
||||||
"@simplewebauthn/server": "10.0.1",
|
"@simplewebauthn/server": "catalog:",
|
||||||
"@socket.io/redis-adapter": "8.3.0",
|
"@socket.io/redis-adapter": "catalog:",
|
||||||
"@socket.io/redis-emitter": "5.1.0",
|
"@socket.io/redis-emitter": "catalog:",
|
||||||
"@typegoose/auto-increment": "4.13.0",
|
"@typegoose/auto-increment": "catalog:",
|
||||||
"@typegoose/typegoose": "12.15.0",
|
"@typegoose/typegoose": "catalog:",
|
||||||
"@types/jsonwebtoken": "9.0.9",
|
"@types/jsonwebtoken": "catalog:",
|
||||||
"algoliasearch": "4.24.0",
|
"algoliasearch": "catalog:",
|
||||||
"axios": "^1.9.0",
|
"axios": "catalog:",
|
||||||
"axios-retry": "4.5.0",
|
"axios-retry": "catalog:",
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "catalog:",
|
||||||
"blurhash": "2.0.5",
|
"blurhash": "catalog:",
|
||||||
"cache-manager": "6.4.2",
|
"cache-manager": "catalog:",
|
||||||
"class-transformer": "0.5.1",
|
"class-transformer": "catalog:",
|
||||||
"class-validator": "0.13.2",
|
"class-validator": "catalog:",
|
||||||
"class-validator-jsonschema": "npm:@innei/class-validator-jsonschema@3.1.2",
|
"class-validator-jsonschema": "catalog:",
|
||||||
"cls-hooked": "^4.2.2",
|
"cls-hooked": "catalog:",
|
||||||
"commander": "13.1.0",
|
"commander": "catalog:",
|
||||||
"dayjs": "1.11.13",
|
"dayjs": "catalog:",
|
||||||
"ejs": "3.1.10",
|
"ejs": "catalog:",
|
||||||
"form-data": "4.0.2",
|
"form-data": "catalog:",
|
||||||
"inquirer": "^10.2.2",
|
"inquirer": "catalog:",
|
||||||
"isbot": "5.1.27",
|
"isbot": "catalog:",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "catalog:",
|
||||||
"json5": "2.2.3",
|
"json5": "catalog:",
|
||||||
"jsonwebtoken": "9.0.2",
|
"jsonwebtoken": "catalog:",
|
||||||
"jszip": "3.10.1",
|
"jszip": "catalog:",
|
||||||
"keyv": "5.3.3",
|
"keyv": "catalog:",
|
||||||
"langchain": "0.3.24",
|
"langchain": "catalog:",
|
||||||
"linkedom": "0.18.10",
|
"linkedom": "catalog:",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "catalog:",
|
||||||
"lru-cache": "11.1.0",
|
"lru-cache": "catalog:",
|
||||||
"marked": "15.0.11",
|
"marked": "catalog:",
|
||||||
"mime-types": "^3.0.1",
|
"mime-types": "catalog:",
|
||||||
"mkdirp": "^3.0.1",
|
"mkdirp": "catalog:",
|
||||||
"mongoose": "8.14.1",
|
"mongoose": "catalog:",
|
||||||
"mongoose-aggregate-paginate-v2": "1.1.4",
|
"mongoose-aggregate-paginate-v2": "catalog:",
|
||||||
"mongoose-autopopulate": "1.1.0",
|
"mongoose-autopopulate": "catalog:",
|
||||||
"mongoose-lean-getters": "2.2.1",
|
"mongoose-lean-getters": "catalog:",
|
||||||
"mongoose-lean-virtuals": "1.1.0",
|
"mongoose-lean-virtuals": "catalog:",
|
||||||
"mongoose-paginate-v2": "1.9.0",
|
"mongoose-paginate-v2": "catalog:",
|
||||||
"node-machine-id": "1.1.12",
|
"node-machine-id": "catalog:",
|
||||||
"nodemailer": "7.0.0",
|
"nodemailer": "catalog:",
|
||||||
"openai": "4.97.0",
|
"openai": "catalog:",
|
||||||
"pluralize": "^8.0.0",
|
"pluralize": "catalog:",
|
||||||
"qs": "6.14.0",
|
"qs": "catalog:",
|
||||||
"reflect-metadata": "0.2.2",
|
"reflect-metadata": "catalog:",
|
||||||
"remove-markdown": "0.6.2",
|
"remove-markdown": "catalog:",
|
||||||
"remove-md-codeblock": "0.0.4",
|
"remove-md-codeblock": "catalog:",
|
||||||
"rxjs": "7.8.2",
|
"rxjs": "catalog:",
|
||||||
"semver": "7.7.1",
|
"semver": "catalog:",
|
||||||
"slugify": "1.6.6",
|
"slugify": "catalog:",
|
||||||
"snakecase-keys": "6.0.0",
|
"snakecase-keys": "catalog:",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "catalog:",
|
||||||
"ua-parser-js": "2.0.3",
|
"ua-parser-js": "catalog:",
|
||||||
"vm2": "3.9.19",
|
"vm2": "catalog:",
|
||||||
"wildcard-match": "5.1.4",
|
"wildcard-match": "catalog:",
|
||||||
"xss": "1.0.15",
|
"xss": "catalog:",
|
||||||
"zx-cjs": "7.0.7-0"
|
"zx-cjs": "catalog:"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@langchain/core": "0.3.51",
|
"@langchain/core": "catalog:",
|
||||||
"@nestjs/cli": "11.0.7",
|
"@nestjs/cli": "catalog:",
|
||||||
"@nestjs/schematics": "11.0.5",
|
"@nestjs/schematics": "catalog:",
|
||||||
"@nestjs/testing": "11.1.0",
|
"@nestjs/testing": "catalog:",
|
||||||
"@swc/core": "1.11.24",
|
"@swc/core": "catalog:",
|
||||||
"@types/babel__core": "7.20.5",
|
"@types/babel__core": "catalog:",
|
||||||
"@types/bcryptjs": "^3.0.0",
|
"@types/bcryptjs": "catalog:",
|
||||||
"@types/cls-hooked": "^4.3.9",
|
"@types/cls-hooked": "catalog:",
|
||||||
"@types/ejs": "3.1.5",
|
"@types/ejs": "catalog:",
|
||||||
"@types/get-image-colors": "4.0.5",
|
"@types/get-image-colors": "catalog:",
|
||||||
"@types/js-yaml": "4.0.9",
|
"@types/js-yaml": "catalog:",
|
||||||
"@types/lodash": "4.17.16",
|
"@types/lodash": "catalog:",
|
||||||
"@types/mime-types": "2.1.4",
|
"@types/mime-types": "catalog:",
|
||||||
"@types/mongoose-aggregate-paginate-v2": "1.0.12",
|
"@types/mongoose-aggregate-paginate-v2": "catalog:",
|
||||||
"@types/node": "22.15.3",
|
"@types/node": "catalog:",
|
||||||
"@types/nodemailer": "6.4.17",
|
"@types/nodemailer": "catalog:",
|
||||||
"@types/qs": "6.9.18",
|
"@types/qs": "catalog:",
|
||||||
"@types/remove-markdown": "0.3.4",
|
"@types/remove-markdown": "catalog:",
|
||||||
"@types/semver": "7.7.0",
|
"@types/semver": "catalog:",
|
||||||
"@types/ua-parser-js": "0.7.39",
|
"@types/ua-parser-js": "catalog:",
|
||||||
"@types/validator": "13.15.0",
|
"@types/validator": "catalog:",
|
||||||
"@vercel/ncc": "0.38.3",
|
"@vercel/ncc": "catalog:",
|
||||||
"cron": "^3.5.0",
|
"cron": "catalog:",
|
||||||
"ioredis": "5.6.1",
|
"ioredis": "catalog:",
|
||||||
"sharp": "0.34.1",
|
"sharp": "catalog:",
|
||||||
"socket.io": "^4.8.1",
|
"socket.io": "catalog:",
|
||||||
"unplugin-swc": "1.5.2",
|
"unplugin-swc": "catalog:",
|
||||||
"vite": "5.4.10",
|
"vite": "catalog:",
|
||||||
"vite-tsconfig-paths": "5.1.4",
|
"vite-tsconfig-paths": "catalog:",
|
||||||
"vitest": "1.5.2",
|
"vitest": "catalog:",
|
||||||
"zx": "7.2.3"
|
"zx": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,6 +42,7 @@ import { HelperModule as BizHelperModule } from './modules/helper/helper.module'
|
|||||||
import { InitModule } from './modules/init/init.module'
|
import { InitModule } from './modules/init/init.module'
|
||||||
import { LinkModule } from './modules/link/link.module'
|
import { LinkModule } from './modules/link/link.module'
|
||||||
import { MarkdownModule } from './modules/markdown/markdown.module'
|
import { MarkdownModule } from './modules/markdown/markdown.module'
|
||||||
|
import { McpModule } from './modules/mcp/mcp.module'
|
||||||
import { NoteModule } from './modules/note/note.module'
|
import { NoteModule } from './modules/note/note.module'
|
||||||
import { OptionModule } from './modules/option/option.module'
|
import { OptionModule } from './modules/option/option.module'
|
||||||
import { PageModule } from './modules/page/page.module'
|
import { PageModule } from './modules/page/page.module'
|
||||||
@@ -94,6 +95,7 @@ import { RedisModule } from './processors/redis/redis.module'
|
|||||||
HealthModule,
|
HealthModule,
|
||||||
LinkModule,
|
LinkModule,
|
||||||
MarkdownModule,
|
MarkdownModule,
|
||||||
|
McpModule,
|
||||||
NoteModule,
|
NoteModule,
|
||||||
OptionModule,
|
OptionModule,
|
||||||
PageModule,
|
PageModule,
|
||||||
|
|||||||
13
apps/core/src/modules/ai/ai-agent/ai-agent.module.ts
Normal file
13
apps/core/src/modules/ai/ai-agent/ai-agent.module.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { forwardRef, Module } from '@nestjs/common'
|
||||||
|
|
||||||
|
import { McpModule } from '../../mcp/mcp.module'
|
||||||
|
import { AiModule } from '../ai.module'
|
||||||
|
import { AIAgentService } from './ai-agent.service'
|
||||||
|
import { TestController } from './test.controller'
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [McpModule, forwardRef(() => AiModule)],
|
||||||
|
providers: [AIAgentService],
|
||||||
|
controllers: isDev ? [TestController] : [],
|
||||||
|
})
|
||||||
|
export class AiAgentModule {}
|
||||||
490
apps/core/src/modules/ai/ai-agent/ai-agent.service.ts
Normal file
490
apps/core/src/modules/ai/ai-agent/ai-agent.service.ts
Normal file
@@ -0,0 +1,490 @@
|
|||||||
|
import { AgentExecutor, createOpenAIToolsAgent } from 'langchain/agents'
|
||||||
|
|
||||||
|
import {
|
||||||
|
ChatPromptTemplate,
|
||||||
|
MessagesPlaceholder,
|
||||||
|
} from '@langchain/core/prompts'
|
||||||
|
import { DynamicStructuredTool, ToolInterface } from '@langchain/core/tools'
|
||||||
|
import { z } from '@mx-space/compiled/zod'
|
||||||
|
import { Injectable } from '@nestjs/common'
|
||||||
|
|
||||||
|
import { McpService } from '../../mcp/mcp.service'
|
||||||
|
import { AiService } from '../ai.service'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AIAgentService {
|
||||||
|
constructor(
|
||||||
|
private readonly aiService: AiService,
|
||||||
|
private readonly mcpService: McpService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
// 创建获取帖子的工具
|
||||||
|
private createGetPostTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_post_by_id',
|
||||||
|
description: '根据ID获取博客文章',
|
||||||
|
schema: z.object({
|
||||||
|
id: z.string().describe('帖子的ID'),
|
||||||
|
}),
|
||||||
|
func: async ({ id }) => {
|
||||||
|
try {
|
||||||
|
const post = await this.mcpService.getPostById(id)
|
||||||
|
return JSON.stringify(post)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取帖子列表的工具
|
||||||
|
private createGetPostsTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_posts',
|
||||||
|
description: '获取博客文章列表',
|
||||||
|
schema: z.object({
|
||||||
|
page: z.number().optional().describe('页码,默认为1'),
|
||||||
|
size: z.number().optional().describe('每页数量,默认为10'),
|
||||||
|
}),
|
||||||
|
func: async ({ page = 1, size = 10 }) => {
|
||||||
|
try {
|
||||||
|
const posts = await this.mcpService.getPosts(page, size)
|
||||||
|
return JSON.stringify(posts)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取笔记的工具
|
||||||
|
private createGetNoteTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_note_by_id',
|
||||||
|
description: '根据ID获取笔记',
|
||||||
|
schema: z.object({
|
||||||
|
id: z.string().describe('笔记的ID或nid'),
|
||||||
|
}),
|
||||||
|
func: async ({ id }) => {
|
||||||
|
try {
|
||||||
|
const note = await this.mcpService.getNoteById(id)
|
||||||
|
return JSON.stringify(note)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取笔记列表的工具
|
||||||
|
private createGetNotesTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_notes',
|
||||||
|
description: '获取笔记列表',
|
||||||
|
schema: z.object({
|
||||||
|
page: z.number().optional().describe('页码,默认为1'),
|
||||||
|
size: z.number().optional().describe('每页数量,默认为10'),
|
||||||
|
}),
|
||||||
|
func: async ({ page = 1, size = 10 }) => {
|
||||||
|
try {
|
||||||
|
const notes = await this.mcpService.getNotes(page, size)
|
||||||
|
return JSON.stringify(notes)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private createGetLatestPostTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_latest_post',
|
||||||
|
description: '获取最新的一篇博客文章',
|
||||||
|
func: async () => {
|
||||||
|
const post = await this.mcpService.getLatestPost()
|
||||||
|
return JSON.stringify(post)
|
||||||
|
},
|
||||||
|
schema: z.object({}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private createGetLatestNotesTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_latest_notes',
|
||||||
|
description: '获取最新的一篇笔记',
|
||||||
|
func: async () => {
|
||||||
|
const notes = await this.mcpService.getLatestNotes()
|
||||||
|
return JSON.stringify(notes)
|
||||||
|
},
|
||||||
|
schema: z.object({}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取分类的工具
|
||||||
|
private createGetCategoryTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_category_by_id',
|
||||||
|
description: '根据ID获取分类',
|
||||||
|
schema: z.object({
|
||||||
|
id: z.string().describe('分类的ID'),
|
||||||
|
}),
|
||||||
|
func: async ({ id }) => {
|
||||||
|
try {
|
||||||
|
const category = await this.mcpService.getCategoryById(id)
|
||||||
|
return JSON.stringify(category)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取所有分类的工具
|
||||||
|
private createGetAllCategoriesTools(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_all_categories',
|
||||||
|
description: '获取所有分类及其文章数量',
|
||||||
|
schema: z.object({}),
|
||||||
|
func: async () => {
|
||||||
|
try {
|
||||||
|
const categories = await this.mcpService.getAllCategories()
|
||||||
|
return JSON.stringify(categories)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取分类下文章的工具
|
||||||
|
private createGetPostsByCategoryTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_posts_by_category',
|
||||||
|
description: '获取指定分类下的所有文章',
|
||||||
|
schema: z.object({
|
||||||
|
categoryId: z.string().describe('分类的ID'),
|
||||||
|
}),
|
||||||
|
func: async ({ categoryId }) => {
|
||||||
|
try {
|
||||||
|
const posts = await this.mcpService.getPostsByCategory(categoryId)
|
||||||
|
return JSON.stringify(posts)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取标签统计的工具
|
||||||
|
private createGetTagsSummaryTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_tags_summary',
|
||||||
|
description: '获取所有标签及其文章数量统计',
|
||||||
|
schema: z.object({}),
|
||||||
|
func: async () => {
|
||||||
|
try {
|
||||||
|
const tags = await this.mcpService.getTagsSummary()
|
||||||
|
return JSON.stringify(tags)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取标签下文章的工具
|
||||||
|
private createGetPostsByTagTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_posts_by_tag',
|
||||||
|
description: '获取指定标签下的所有文章',
|
||||||
|
schema: z.object({
|
||||||
|
tag: z.string().describe('标签名称'),
|
||||||
|
}),
|
||||||
|
func: async ({ tag }) => {
|
||||||
|
try {
|
||||||
|
const posts = await this.mcpService.getPostsByTag(tag)
|
||||||
|
return JSON.stringify(posts)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取页面的工具
|
||||||
|
private createGetPageTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_page_by_id',
|
||||||
|
description: '根据ID获取页面',
|
||||||
|
schema: z.object({
|
||||||
|
id: z.string().describe('页面的ID'),
|
||||||
|
}),
|
||||||
|
func: async ({ id }) => {
|
||||||
|
try {
|
||||||
|
const page = await this.mcpService.getPageById(id)
|
||||||
|
return JSON.stringify(page)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取所有页面的工具
|
||||||
|
private createGetAllPagesTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_all_pages',
|
||||||
|
description: '获取所有页面',
|
||||||
|
schema: z.object({}),
|
||||||
|
func: async () => {
|
||||||
|
try {
|
||||||
|
const pages = await this.mcpService.getAllPages()
|
||||||
|
return JSON.stringify(pages)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取所有说说的工具
|
||||||
|
private createGetAllSaysTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_all_says',
|
||||||
|
description: '获取所有说说/状态更新',
|
||||||
|
schema: z.object({}),
|
||||||
|
func: async () => {
|
||||||
|
try {
|
||||||
|
const says = await this.mcpService.getAllSays()
|
||||||
|
return JSON.stringify(says)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取随机说说的工具
|
||||||
|
private createGetRandomSayTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_random_say',
|
||||||
|
description: '获取随机一条说说/状态更新',
|
||||||
|
schema: z.object({}),
|
||||||
|
func: async () => {
|
||||||
|
try {
|
||||||
|
const say = await this.mcpService.getRandomSay()
|
||||||
|
return JSON.stringify(say)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取所有动态的工具
|
||||||
|
private createGetAllRecentlyTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_all_recently',
|
||||||
|
description: '获取所有动态/活动',
|
||||||
|
schema: z.object({}),
|
||||||
|
func: async () => {
|
||||||
|
try {
|
||||||
|
const recently = await this.mcpService.getAllRecently()
|
||||||
|
return JSON.stringify(recently)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取特定动态的工具
|
||||||
|
private createGetRecentlyByIdTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_recently_by_id',
|
||||||
|
description: '根据ID获取特定动态/活动',
|
||||||
|
schema: z.object({
|
||||||
|
id: z.string().describe('动态的ID'),
|
||||||
|
}),
|
||||||
|
func: async ({ id }) => {
|
||||||
|
try {
|
||||||
|
const recently = await this.mcpService.getRecentlyById(id)
|
||||||
|
return JSON.stringify(recently)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取最新动态的工具
|
||||||
|
private createGetLatestRecentlyTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_latest_recently',
|
||||||
|
description: '获取最新的一条动态/活动',
|
||||||
|
schema: z.object({}),
|
||||||
|
func: async () => {
|
||||||
|
try {
|
||||||
|
const recently = await this.mcpService.getLatestRecently()
|
||||||
|
return JSON.stringify(recently)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取分页动态的工具
|
||||||
|
private createGetRecentlyOffsetTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_recently_offset',
|
||||||
|
description: '获取指定范围的动态/活动',
|
||||||
|
schema: z.object({
|
||||||
|
size: z.number().optional().describe('数量,默认为10'),
|
||||||
|
before: z.string().optional().describe('获取此ID之前的动态'),
|
||||||
|
after: z.string().optional().describe('获取此ID之后的动态'),
|
||||||
|
}),
|
||||||
|
func: async ({ size = 10, before, after }) => {
|
||||||
|
try {
|
||||||
|
const recently = await this.mcpService.getRecentlyOffset({
|
||||||
|
size,
|
||||||
|
before,
|
||||||
|
after,
|
||||||
|
})
|
||||||
|
return JSON.stringify(recently)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取评论列表的工具
|
||||||
|
private createGetCommentsTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_comments',
|
||||||
|
description: '获取所有评论,可按状态筛选',
|
||||||
|
schema: z.object({
|
||||||
|
page: z.number().optional().describe('页码,默认为1'),
|
||||||
|
size: z.number().optional().describe('每页数量,默认为10'),
|
||||||
|
state: z.number().optional().describe('评论状态筛选,0表示所有'),
|
||||||
|
}),
|
||||||
|
func: async ({ page = 1, size = 10, state = 0 }) => {
|
||||||
|
try {
|
||||||
|
const comments = await this.mcpService.getComments({
|
||||||
|
page,
|
||||||
|
size,
|
||||||
|
state,
|
||||||
|
})
|
||||||
|
return JSON.stringify(comments)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建获取内容评论的工具
|
||||||
|
private createGetContentCommentsTool(): ToolInterface {
|
||||||
|
return new DynamicStructuredTool({
|
||||||
|
name: 'get_content_comments',
|
||||||
|
description: '获取特定内容的评论',
|
||||||
|
schema: z.object({
|
||||||
|
id: z.string().describe('内容的ID'),
|
||||||
|
type: z.string().optional().describe('内容类型,如post, note, page等'),
|
||||||
|
}),
|
||||||
|
func: async ({ id, type }) => {
|
||||||
|
try {
|
||||||
|
const comments = await this.mcpService.getContentComments(id, type)
|
||||||
|
return JSON.stringify(comments)
|
||||||
|
} catch (error) {
|
||||||
|
return `Error: ${error.message}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用LangChain的Agent模式与MCP数据交互
|
||||||
|
async runWithTools(userPrompt: string) {
|
||||||
|
// 获取OpenAI模型
|
||||||
|
const model = await this.aiService.getOpenAiChain()
|
||||||
|
|
||||||
|
// 初始化工具列表
|
||||||
|
const tools = [
|
||||||
|
this.createGetPostTool(),
|
||||||
|
this.createGetPostsTool(),
|
||||||
|
this.createGetNoteTool(),
|
||||||
|
this.createGetNotesTool(),
|
||||||
|
this.createGetLatestPostTool(),
|
||||||
|
this.createGetLatestNotesTool(),
|
||||||
|
this.createGetCategoryTool(),
|
||||||
|
this.createGetAllCategoriesTools(),
|
||||||
|
this.createGetPostsByCategoryTool(),
|
||||||
|
this.createGetTagsSummaryTool(),
|
||||||
|
this.createGetPostsByTagTool(),
|
||||||
|
this.createGetPageTool(),
|
||||||
|
this.createGetAllPagesTool(),
|
||||||
|
this.createGetAllSaysTool(),
|
||||||
|
this.createGetRandomSayTool(),
|
||||||
|
this.createGetAllRecentlyTool(),
|
||||||
|
this.createGetRecentlyByIdTool(),
|
||||||
|
this.createGetLatestRecentlyTool(),
|
||||||
|
this.createGetRecentlyOffsetTool(),
|
||||||
|
this.createGetCommentsTool(),
|
||||||
|
this.createGetContentCommentsTool(),
|
||||||
|
]
|
||||||
|
|
||||||
|
// 创建Agent提示模板
|
||||||
|
const prompt = ChatPromptTemplate.fromMessages([
|
||||||
|
[
|
||||||
|
'system',
|
||||||
|
`你是一个可以访问博客数据库的智能助手。使用提供的工具来获取和分析数据。
|
||||||
|
|
||||||
|
当你需要回答用户问题时,请遵循以下步骤:
|
||||||
|
1. 分析用户的问题,确定需要获取什么数据
|
||||||
|
2. 使用合适的工具获取数据
|
||||||
|
3. 检查和分析获取的数据
|
||||||
|
4. 如需更多信息,继续使用工具获取
|
||||||
|
5. 根据所有收集到的数据提供完整回答
|
||||||
|
|
||||||
|
你可以查询的内容包括:
|
||||||
|
- 博客文章(posts)
|
||||||
|
- 笔记(notes)
|
||||||
|
- 分类(categories)
|
||||||
|
- 标签(tags)
|
||||||
|
- 自定义页面(pages)
|
||||||
|
- 说说/状态更新(says)
|
||||||
|
- 动态/活动(recently)
|
||||||
|
- 评论(comments)
|
||||||
|
|
||||||
|
不要编造信息,只使用通过工具获得的真实数据。`,
|
||||||
|
],
|
||||||
|
new MessagesPlaceholder('chat_history'),
|
||||||
|
['human', '{input}'],
|
||||||
|
new MessagesPlaceholder('agent_scratchpad'),
|
||||||
|
])
|
||||||
|
|
||||||
|
// 创建Agent
|
||||||
|
const agent = await createOpenAIToolsAgent({
|
||||||
|
llm: model,
|
||||||
|
tools,
|
||||||
|
prompt,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 创建Agent执行器
|
||||||
|
const executor = new AgentExecutor({
|
||||||
|
agent,
|
||||||
|
tools,
|
||||||
|
maxIterations: 5,
|
||||||
|
verbose: isDev,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 执行Agent
|
||||||
|
const result = await executor.invoke({
|
||||||
|
input: userPrompt,
|
||||||
|
chat_history: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
return result.output
|
||||||
|
}
|
||||||
|
}
|
||||||
15
apps/core/src/modules/ai/ai-agent/test.controller.ts
Normal file
15
apps/core/src/modules/ai/ai-agent/test.controller.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { Controller, Get } from '@nestjs/common'
|
||||||
|
|
||||||
|
import { AIAgentService } from './ai-agent.service'
|
||||||
|
|
||||||
|
@Controller('ai/test')
|
||||||
|
export class TestController {
|
||||||
|
constructor(private readonly aiAgentService: AIAgentService) {}
|
||||||
|
|
||||||
|
@Get('/')
|
||||||
|
async test() {
|
||||||
|
return this.aiAgentService.runWithTools(
|
||||||
|
'Posts Id: 65e99e28eb677674816310c7 主要了写了什么内容',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import { JsonOutputFunctionsParser } from 'langchain/output_parsers'
|
|||||||
import removeMdCodeblock from 'remove-md-codeblock'
|
import removeMdCodeblock from 'remove-md-codeblock'
|
||||||
import type { PagerDto } from '~/shared/dto/pager.dto'
|
import type { PagerDto } from '~/shared/dto/pager.dto'
|
||||||
|
|
||||||
|
import { JsonOutputToolsParser } from '@langchain/core/output_parsers/openai_tools'
|
||||||
import { Injectable, Logger } from '@nestjs/common'
|
import { Injectable, Logger } from '@nestjs/common'
|
||||||
import { OnEvent } from '@nestjs/event-emitter'
|
import { OnEvent } from '@nestjs/event-emitter'
|
||||||
|
|
||||||
@@ -57,33 +58,42 @@ export class AiSummaryService {
|
|||||||
throw new BizException(ErrorCodeEnum.ContentNotFoundCantProcess)
|
throw new BizException(ErrorCodeEnum.ContentNotFoundCantProcess)
|
||||||
}
|
}
|
||||||
|
|
||||||
const parser = new JsonOutputFunctionsParser()
|
const parser = new JsonOutputToolsParser()
|
||||||
|
|
||||||
const runnable = openai
|
const runnable = openai
|
||||||
.bind({
|
.bind({
|
||||||
functions: [
|
tools: [
|
||||||
{
|
{
|
||||||
name: 'extractor',
|
type: 'function',
|
||||||
parameters: {
|
function: {
|
||||||
type: 'object',
|
name: 'extractor',
|
||||||
properties: {
|
description: `Extract the summary of the input text in the ${LANGUAGE_CODE_TO_NAME[lang] || LANGUAGE_CODE_TO_NAME[DEFAULT_SUMMARY_LANG]}, and the length of the summary is less than 150 words.`,
|
||||||
summary: {
|
parameters: {
|
||||||
type: 'string',
|
type: 'object',
|
||||||
description: `The summary of the input text in the ${LANGUAGE_CODE_TO_NAME[lang] || LANGUAGE_CODE_TO_NAME[DEFAULT_SUMMARY_LANG]}, and the length of the summary is less than 150 words.`,
|
properties: {
|
||||||
|
summary: {
|
||||||
|
type: 'string',
|
||||||
|
description: `The summary of the input text in the ${LANGUAGE_CODE_TO_NAME[lang] || LANGUAGE_CODE_TO_NAME[DEFAULT_SUMMARY_LANG]}, and the length of the summary is less than 150 words.`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
required: ['summary'],
|
||||||
},
|
},
|
||||||
required: ['summary'],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
function_call: { name: 'extractor' },
|
|
||||||
|
tool_choice: { type: 'function', function: { name: 'extractor' } },
|
||||||
})
|
})
|
||||||
.pipe(parser)
|
.pipe(parser)
|
||||||
const result = await runnable.invoke([
|
const result = (await runnable.invoke([
|
||||||
this.serializeText(article.document.text),
|
this.serializeText(article.document.text),
|
||||||
])
|
])) as any[]
|
||||||
|
|
||||||
return (result as any).summary
|
if (result.length === 0) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result[0]?.args?.summary
|
||||||
}
|
}
|
||||||
async generateSummaryByOpenAI(articleId: string, lang: string) {
|
async generateSummaryByOpenAI(articleId: string, lang: string) {
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { JsonOutputFunctionsParser } from 'langchain/output_parsers'
|
import type {
|
||||||
import type { FunctionDefinition } from '@langchain/core/language_models/base'
|
FunctionDefinition,
|
||||||
|
ToolDefinition,
|
||||||
|
} from '@langchain/core/language_models/base'
|
||||||
|
|
||||||
|
import { JsonOutputToolsParser } from '@langchain/core/output_parsers/openai_tools'
|
||||||
import { Injectable, Logger } from '@nestjs/common'
|
import { Injectable, Logger } from '@nestjs/common'
|
||||||
|
|
||||||
import { AiService } from '../ai.service'
|
import { AiService } from '../ai.service'
|
||||||
@@ -16,23 +19,30 @@ export class AiWriterService {
|
|||||||
text: string,
|
text: string,
|
||||||
parameters: FunctionDefinition['parameters'],
|
parameters: FunctionDefinition['parameters'],
|
||||||
) {
|
) {
|
||||||
const functionSchema: FunctionDefinition = {
|
const toolDefinition: ToolDefinition = {
|
||||||
name: 'extractor',
|
type: 'function',
|
||||||
description: 'Extracts fields from the input.',
|
function: {
|
||||||
parameters,
|
name: 'extractor',
|
||||||
|
description: 'Extracts fields from the input.',
|
||||||
|
parameters,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
const model = await this.aiService.getOpenAiChain()
|
const model = await this.aiService.getOpenAiChain()
|
||||||
const parser = new JsonOutputFunctionsParser()
|
const parser = new JsonOutputToolsParser()
|
||||||
|
|
||||||
const runnable = model
|
const runnable = model
|
||||||
.bind({
|
.bind({
|
||||||
functions: [functionSchema],
|
tools: [toolDefinition],
|
||||||
function_call: { name: 'extractor' },
|
tool_choice: { type: 'function', function: { name: 'extractor' } },
|
||||||
})
|
})
|
||||||
.pipe(parser)
|
.pipe(parser)
|
||||||
const result = await runnable.invoke([text])
|
const result = (await runnable.invoke([text])) as any[]
|
||||||
|
|
||||||
return result
|
if (result.length === 0) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
// Extract just the args object from the first tool call response
|
||||||
|
return result[0]?.args || {}
|
||||||
}
|
}
|
||||||
async generateTitleAndSlugByOpenAI(text: string) {
|
async generateTitleAndSlugByOpenAI(text: string) {
|
||||||
return this.queryByFunctionSchema(text, {
|
return this.queryByFunctionSchema(text, {
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import type { ChatModel } from 'openai/resources'
|
|
||||||
|
|
||||||
export const DEFAULT_SUMMARY_LANG = 'zh'
|
export const DEFAULT_SUMMARY_LANG = 'zh'
|
||||||
type _Models = ChatModel
|
|
||||||
export const LANGUAGE_CODE_TO_NAME = {
|
export const LANGUAGE_CODE_TO_NAME = {
|
||||||
ar: 'Arabic',
|
ar: 'Arabic',
|
||||||
bg: 'Bulgarian',
|
bg: 'Bulgarian',
|
||||||
@@ -46,150 +43,3 @@ export const LANGUAGE_CODE_TO_NAME = {
|
|||||||
vi: 'Vietnamese',
|
vi: 'Vietnamese',
|
||||||
zh: 'Chinese',
|
zh: 'Chinese',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const OpenAiSupportedModels = [
|
|
||||||
{
|
|
||||||
label: 'o3-mini',
|
|
||||||
value: 'o3-mini',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'o3-mini-2025-01-31',
|
|
||||||
value: 'o3-mini-2025-01-31',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'o1',
|
|
||||||
value: 'o1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'o1-2024-12-17',
|
|
||||||
value: 'o1-2024-12-17',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'o1-preview',
|
|
||||||
value: 'o1-preview',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'o1-preview-2024-09-12',
|
|
||||||
value: 'o1-preview-2024-09-12',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'o1-mini',
|
|
||||||
value: 'o1-mini',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'o1-mini-2024-09-12',
|
|
||||||
value: 'o1-mini-2024-09-12',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4o',
|
|
||||||
value: 'gpt-4o',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4o-2024-11-20',
|
|
||||||
value: 'gpt-4o-2024-11-20',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4o-2024-08-06',
|
|
||||||
value: 'gpt-4o-2024-08-06',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4o-2024-05-13',
|
|
||||||
value: 'gpt-4o-2024-05-13',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4o-audio-preview',
|
|
||||||
value: 'gpt-4o-audio-preview',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4o-audio-preview-2024-10-01',
|
|
||||||
value: 'gpt-4o-audio-preview-2024-10-01',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4o-audio-preview-2024-12-17',
|
|
||||||
value: 'gpt-4o-audio-preview-2024-12-17',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4o-mini-audio-preview',
|
|
||||||
value: 'gpt-4o-mini-audio-preview',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4o-mini-2024-07-18',
|
|
||||||
value: 'gpt-4o-mini-2024-07-18',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4-turbo',
|
|
||||||
value: 'gpt-4-turbo',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4-turbo-2024-04-09',
|
|
||||||
value: 'gpt-4-turbo-2024-04-09',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4-0125-preview',
|
|
||||||
value: 'gpt-4-0125-preview',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4-turbo-preview',
|
|
||||||
value: 'gpt-4-turbo-preview',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4-1106-preview',
|
|
||||||
value: 'gpt-4-1106-preview',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4-vision-preview',
|
|
||||||
value: 'gpt-4-vision-preview',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4',
|
|
||||||
value: 'gpt-4',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4-0314',
|
|
||||||
value: 'gpt-4-0314',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4-0613',
|
|
||||||
value: 'gpt-4-0613',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4-32k',
|
|
||||||
value: 'gpt-4-32k',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4-32k-0314',
|
|
||||||
value: 'gpt-4-32k-0314',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-4-32k-0613',
|
|
||||||
value: 'gpt-4-32k-0613',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-3.5-turbo',
|
|
||||||
value: 'gpt-3.5-turbo',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-3.5-turbo-16k',
|
|
||||||
value: 'gpt-3.5-turbo-16k',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-3.5-turbo-0301',
|
|
||||||
value: 'gpt-3.5-turbo-0301',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-3.5-turbo-0613',
|
|
||||||
value: 'gpt-3.5-turbo-0613',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-3.5-turbo-1106',
|
|
||||||
value: 'gpt-3.5-turbo-1106',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-3.5-turbo-0125',
|
|
||||||
value: 'gpt-3.5-turbo-0125',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'gpt-3.5-turbo-16k-0613',
|
|
||||||
value: 'gpt-3.5-turbo-16k-0613',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Module } from '@nestjs/common'
|
import { forwardRef, Module } from '@nestjs/common'
|
||||||
|
|
||||||
|
import { AiAgentModule } from './ai-agent/ai-agent.module'
|
||||||
import { AiSummaryController } from './ai-summary/ai-summary.controller'
|
import { AiSummaryController } from './ai-summary/ai-summary.controller'
|
||||||
import { AiSummaryService } from './ai-summary/ai-summary.service'
|
import { AiSummaryService } from './ai-summary/ai-summary.service'
|
||||||
import { AiWriterController } from './ai-writer/ai-writer.controller'
|
import { AiWriterController } from './ai-writer/ai-writer.controller'
|
||||||
@@ -7,6 +8,7 @@ import { AiWriterService } from './ai-writer/ai-writer.service'
|
|||||||
import { AiService } from './ai.service'
|
import { AiService } from './ai.service'
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
imports: [forwardRef(() => AiAgentModule)],
|
||||||
providers: [AiSummaryService, AiService, AiWriterService],
|
providers: [AiSummaryService, AiService, AiWriterService],
|
||||||
controllers: [AiSummaryController, AiWriterController],
|
controllers: [AiSummaryController, AiWriterController],
|
||||||
exports: [AiService],
|
exports: [AiService],
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export const generateDefaultConfig: () => IConfig = () => ({
|
|||||||
enableAutoGenerateSummary: false,
|
enableAutoGenerateSummary: false,
|
||||||
enableSummary: false,
|
enableSummary: false,
|
||||||
openAiEndpoint: '',
|
openAiEndpoint: '',
|
||||||
openAiPreferredModel: 'gpt-3.5-turbo',
|
openAiPreferredModel: 'gpt-4o-mini',
|
||||||
openAiKey: '',
|
openAiKey: '',
|
||||||
aiSummaryTargetLanguage: 'auto',
|
aiSummaryTargetLanguage: 'auto',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import type { ChatModel } from 'openai/resources'
|
|||||||
|
|
||||||
import { IsAllowedUrl } from '~/decorators/dto/isAllowedUrl'
|
import { IsAllowedUrl } from '~/decorators/dto/isAllowedUrl'
|
||||||
|
|
||||||
import { OpenAiSupportedModels } from '../ai/ai.constants'
|
|
||||||
import { Encrypt } from './configs.encrypt.util'
|
import { Encrypt } from './configs.encrypt.util'
|
||||||
import {
|
import {
|
||||||
halfFieldOption,
|
halfFieldOption,
|
||||||
@@ -431,13 +430,8 @@ export class AIDto {
|
|||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
@JSONSchemaPlainField('OpenAI 默认模型', {
|
@JSONSchemaPlainField('OpenAI 默认模型')
|
||||||
'ui:options': {
|
openAiPreferredModel: string
|
||||||
type: 'select',
|
|
||||||
values: OpenAiSupportedModels,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
openAiPreferredModel: ChatModel
|
|
||||||
|
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
|||||||
26
apps/core/src/modules/mcp/mcp.module.ts
Normal file
26
apps/core/src/modules/mcp/mcp.module.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { forwardRef, Module } from '@nestjs/common'
|
||||||
|
|
||||||
|
import { CategoryModule } from '../category/category.module'
|
||||||
|
import { CommentModule } from '../comment/comment.module'
|
||||||
|
import { NoteModule } from '../note/note.module'
|
||||||
|
import { PageModule } from '../page/page.module'
|
||||||
|
import { PostModule } from '../post/post.module'
|
||||||
|
import { RecentlyModule } from '../recently/recently.module'
|
||||||
|
import { SayModule } from '../say/say.module'
|
||||||
|
import { McpService } from './mcp.service'
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
forwardRef(() => NoteModule),
|
||||||
|
forwardRef(() => PostModule),
|
||||||
|
forwardRef(() => CategoryModule),
|
||||||
|
forwardRef(() => PageModule),
|
||||||
|
forwardRef(() => SayModule),
|
||||||
|
forwardRef(() => RecentlyModule),
|
||||||
|
forwardRef(() => CommentModule),
|
||||||
|
],
|
||||||
|
|
||||||
|
providers: [McpService],
|
||||||
|
exports: [McpService],
|
||||||
|
})
|
||||||
|
export class McpModule {}
|
||||||
327
apps/core/src/modules/mcp/mcp.service.ts
Normal file
327
apps/core/src/modules/mcp/mcp.service.ts
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
import { Injectable } from '@nestjs/common'
|
||||||
|
|
||||||
|
import { CannotFindException } from '~/common/exceptions/cant-find.exception'
|
||||||
|
|
||||||
|
import { CategoryService } from '../category/category.service'
|
||||||
|
import { CommentService } from '../comment/comment.service'
|
||||||
|
import { NoteService } from '../note/note.service'
|
||||||
|
import { PageService } from '../page/page.service'
|
||||||
|
import { PostService } from '../post/post.service'
|
||||||
|
import { RecentlyService } from '../recently/recently.service'
|
||||||
|
import { SayService } from '../say/say.service'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class McpService {
|
||||||
|
constructor(
|
||||||
|
private readonly postService: PostService,
|
||||||
|
private readonly noteService: NoteService,
|
||||||
|
private readonly categoryService: CategoryService,
|
||||||
|
private readonly pageService: PageService,
|
||||||
|
private readonly sayService: SayService,
|
||||||
|
private readonly recentlyService: RecentlyService,
|
||||||
|
private readonly commentService: CommentService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a post by ID
|
||||||
|
* @param id Post ID
|
||||||
|
* @returns The requested post
|
||||||
|
*/
|
||||||
|
async getPostById(id: string) {
|
||||||
|
const post = await this.postService.model
|
||||||
|
.findById(id)
|
||||||
|
.populate('category')
|
||||||
|
.populate({
|
||||||
|
path: 'related',
|
||||||
|
select: 'title slug id _id categoryId category',
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!post) {
|
||||||
|
throw new CannotFindException()
|
||||||
|
}
|
||||||
|
|
||||||
|
return post
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get posts with pagination
|
||||||
|
* @param page Page number
|
||||||
|
* @param size Page size
|
||||||
|
* @returns Paginated posts
|
||||||
|
*/
|
||||||
|
async getPosts(page = 1, size = 10) {
|
||||||
|
const query = this.postService.model
|
||||||
|
.find()
|
||||||
|
.populate('category')
|
||||||
|
.sort({ created: -1 })
|
||||||
|
.skip((page - 1) * size)
|
||||||
|
.limit(size)
|
||||||
|
|
||||||
|
const posts = await query.exec()
|
||||||
|
const total = await this.postService.model.countDocuments()
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: posts,
|
||||||
|
pagination: {
|
||||||
|
total,
|
||||||
|
size,
|
||||||
|
currentPage: page,
|
||||||
|
totalPage: Math.ceil(total / size),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a note by ID
|
||||||
|
* @param id Note ID or nid
|
||||||
|
* @returns The requested note
|
||||||
|
*/
|
||||||
|
async getNoteById(id: string | number) {
|
||||||
|
const note = await this.noteService.findOneByIdOrNid(id)
|
||||||
|
|
||||||
|
if (!note) {
|
||||||
|
throw new CannotFindException()
|
||||||
|
}
|
||||||
|
|
||||||
|
return note
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get notes with pagination
|
||||||
|
* @param page Page number
|
||||||
|
* @param size Page size
|
||||||
|
* @returns Paginated notes
|
||||||
|
*/
|
||||||
|
async getNotes(page = 1, size = 10) {
|
||||||
|
const query = this.noteService.model
|
||||||
|
.find({ hide: false })
|
||||||
|
.sort({ created: -1 })
|
||||||
|
.skip((page - 1) * size)
|
||||||
|
.limit(size)
|
||||||
|
|
||||||
|
const notes = await query.exec()
|
||||||
|
const total = await this.noteService.model.countDocuments({ hide: false })
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: notes,
|
||||||
|
pagination: {
|
||||||
|
total,
|
||||||
|
size,
|
||||||
|
currentPage: page,
|
||||||
|
totalPage: Math.ceil(total / size),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLatestPost() {
|
||||||
|
const post = await this.postService.model.findOne().sort({ created: -1 })
|
||||||
|
|
||||||
|
if (!post) {
|
||||||
|
throw new CannotFindException()
|
||||||
|
}
|
||||||
|
|
||||||
|
return post
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLatestNotes() {
|
||||||
|
const notes = await this.noteService.model.findOne().sort({ created: -1 })
|
||||||
|
|
||||||
|
if (!notes) {
|
||||||
|
throw new CannotFindException()
|
||||||
|
}
|
||||||
|
|
||||||
|
return notes
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a category by ID
|
||||||
|
* @param id Category ID
|
||||||
|
* @returns The requested category with post count
|
||||||
|
*/
|
||||||
|
async getCategoryById(id: string) {
|
||||||
|
const category = await this.categoryService.findCategoryById(id)
|
||||||
|
|
||||||
|
if (!category) {
|
||||||
|
throw new CannotFindException()
|
||||||
|
}
|
||||||
|
|
||||||
|
return category
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all categories
|
||||||
|
* @returns All categories with post counts
|
||||||
|
*/
|
||||||
|
async getAllCategories() {
|
||||||
|
return await this.categoryService.findAllCategory()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get posts in a specific category
|
||||||
|
* @param categoryId Category ID
|
||||||
|
* @returns Posts in the specified category
|
||||||
|
*/
|
||||||
|
async getPostsByCategory(categoryId: string) {
|
||||||
|
const posts = await this.categoryService.findCategoryPost(categoryId)
|
||||||
|
|
||||||
|
if (!posts || posts.length === 0) {
|
||||||
|
throw new CannotFindException()
|
||||||
|
}
|
||||||
|
|
||||||
|
return posts
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a summary of all tags and their post counts
|
||||||
|
* @returns Tags with post counts
|
||||||
|
*/
|
||||||
|
async getTagsSummary() {
|
||||||
|
return await this.categoryService.getPostTagsSum()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get posts with a specific tag
|
||||||
|
* @param tag Tag name
|
||||||
|
* @returns Posts with the specified tag
|
||||||
|
*/
|
||||||
|
async getPostsByTag(tag: string) {
|
||||||
|
return await this.categoryService.findArticleWithTag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a page by ID
|
||||||
|
* @param id Page ID
|
||||||
|
* @returns The requested page
|
||||||
|
*/
|
||||||
|
async getPageById(id: string) {
|
||||||
|
const page = await this.pageService.model.findById(id)
|
||||||
|
|
||||||
|
if (!page) {
|
||||||
|
throw new CannotFindException()
|
||||||
|
}
|
||||||
|
|
||||||
|
return page
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all pages
|
||||||
|
* @returns All pages
|
||||||
|
*/
|
||||||
|
async getAllPages() {
|
||||||
|
const pages = await this.pageService.model.find().sort({ order: 1 })
|
||||||
|
return pages
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all says (quotes/status updates)
|
||||||
|
* @returns All says
|
||||||
|
*/
|
||||||
|
async getAllSays() {
|
||||||
|
const says = await this.sayService.model.find().sort({ created: -1 })
|
||||||
|
return says
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a random say
|
||||||
|
* @returns A random say
|
||||||
|
*/
|
||||||
|
async getRandomSay() {
|
||||||
|
const res = await this.sayService.model.find({}).lean()
|
||||||
|
if (res.length === 0) {
|
||||||
|
throw new CannotFindException()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a random item from the array
|
||||||
|
const randomIndex = Math.floor(Math.random() * res.length)
|
||||||
|
return res[randomIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all recently activity
|
||||||
|
* @returns All recently activity
|
||||||
|
*/
|
||||||
|
async getAllRecently() {
|
||||||
|
return await this.recentlyService.getAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a specific recently activity by ID
|
||||||
|
* @param id Recently activity ID
|
||||||
|
* @returns The requested recently activity
|
||||||
|
*/
|
||||||
|
async getRecentlyById(id: string) {
|
||||||
|
const recently = await this.recentlyService.getOne(id)
|
||||||
|
|
||||||
|
if (!recently) {
|
||||||
|
throw new CannotFindException()
|
||||||
|
}
|
||||||
|
|
||||||
|
return recently
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get latest recently activities with pagination
|
||||||
|
* @param size Number of items to retrieve
|
||||||
|
* @param before Retrieve items before this ID
|
||||||
|
* @param after Retrieve items after this ID
|
||||||
|
* @returns Paginated recently activities
|
||||||
|
*/
|
||||||
|
async getRecentlyOffset({
|
||||||
|
size = 10,
|
||||||
|
before,
|
||||||
|
after,
|
||||||
|
}: {
|
||||||
|
size?: number
|
||||||
|
before?: string
|
||||||
|
after?: string
|
||||||
|
}) {
|
||||||
|
return await this.recentlyService.getOffset({ size, before, after })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the latest recently activity
|
||||||
|
* @returns The latest recently activity
|
||||||
|
*/
|
||||||
|
async getLatestRecently() {
|
||||||
|
const recently = await this.recentlyService.getLatestOne()
|
||||||
|
|
||||||
|
if (!recently) {
|
||||||
|
throw new CannotFindException()
|
||||||
|
}
|
||||||
|
|
||||||
|
return recently
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get comments with pagination
|
||||||
|
* @param page Page number
|
||||||
|
* @param size Page size
|
||||||
|
* @param state Comment state filter (0 = all)
|
||||||
|
* @returns Paginated comments
|
||||||
|
*/
|
||||||
|
async getComments({ page = 1, size = 10, state = 0 } = {}) {
|
||||||
|
return await this.commentService.getComments({ page, size, state })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get comments for a specific content
|
||||||
|
* @param id Content ID
|
||||||
|
* @param type Content type (post, page, note, etc.)
|
||||||
|
* @returns Comments for the specified content
|
||||||
|
*/
|
||||||
|
async getContentComments(id: string, type?: string) {
|
||||||
|
const allowComment = await this.commentService.allowComment(id, type as any)
|
||||||
|
|
||||||
|
if (!allowComment) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const comments = await this.commentService.model.find({
|
||||||
|
ref: id,
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.commentService.fillAndReplaceAvatarUrl(comments)
|
||||||
|
|
||||||
|
return comments
|
||||||
|
}
|
||||||
|
}
|
||||||
52
package.json
52
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "pnpm@9.15.9",
|
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39",
|
||||||
"license": "AGPLv3",
|
"license": "AGPLv3",
|
||||||
"homepage": "https://github.com/mx-space/core#readme",
|
"homepage": "https://github.com/mx-space/core#readme",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -24,23 +24,31 @@
|
|||||||
"redis-memory-server": "0.12.1"
|
"redis-memory-server": "0.12.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"zx-cjs": "7.0.7-0"
|
"zx-cjs": "catalog:"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@innei/prettier": "0.15.0",
|
"@innei/prettier": "catalog:",
|
||||||
"@sxzz/eslint-config": "6.1.1",
|
"@sxzz/eslint-config": "catalog:",
|
||||||
"@types/node": "22.14.0",
|
"@types/node": "catalog:conflicts_@types/node_22_14_0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "catalog:",
|
||||||
"eslint": "^9.24.0",
|
"eslint": "catalog:",
|
||||||
"lint-staged": "15.5.0",
|
"lint-staged": "catalog:",
|
||||||
"prettier": "3.5.3",
|
"prettier": "catalog:",
|
||||||
"rimraf": "6.0.1",
|
"rimraf": "catalog:",
|
||||||
"simple-git-hooks": "2.12.1",
|
"simple-git-hooks": "catalog:",
|
||||||
"ts-node": "10.9.2",
|
"ts-node": "catalog:",
|
||||||
"tsconfig-paths": "4.2.0",
|
"tsconfig-paths": "catalog:",
|
||||||
"tsup": "8.4.0",
|
"tsup": "catalog:",
|
||||||
"typescript": "5.8.3",
|
"typescript": "catalog:",
|
||||||
"vite-tsconfig-paths": "5.1.4"
|
"vite-tsconfig-paths": "catalog:"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"get-pixels@^3>request": "./external/request",
|
||||||
|
"mongodb": "6.12.0",
|
||||||
|
"pino": "./external/pino",
|
||||||
|
"semver": "7.7.1",
|
||||||
|
"typescript": "5.7.3",
|
||||||
|
"whatwg-url": "14.1.1"
|
||||||
},
|
},
|
||||||
"simple-git-hooks": {
|
"simple-git-hooks": {
|
||||||
"pre-commit": "pnpm lint-staged"
|
"pre-commit": "pnpm lint-staged"
|
||||||
@@ -51,13 +59,5 @@
|
|||||||
"prettier --ignore-path ./.prettierignore --write "
|
"prettier --ignore-path ./.prettierignore --write "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"issues": "https://github.com/mx-space/core/issues",
|
"issues": "https://github.com/mx-space/core/issues"
|
||||||
"resolutions": {
|
}
|
||||||
"get-pixels@^3>request": "./external/request",
|
|
||||||
"mongodb": "6.12.0",
|
|
||||||
"pino": "./external/pino",
|
|
||||||
"semver": "7.7.1",
|
|
||||||
"typescript": "5.7.3",
|
|
||||||
"whatwg-url": "14.1.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,14 +6,16 @@
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": "./dist/index.cjs",
|
".": "./dist/index.cjs",
|
||||||
"./zx-global": "./zx-global.cjs",
|
"./zx-global": "./zx-global.cjs",
|
||||||
"./auth": "./dist/auth.cjs"
|
"./auth": "./dist/auth.cjs",
|
||||||
|
"./zod": "./dist/zod.cjs"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsup"
|
"build": "tsup"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"better-auth": "1.2.5",
|
"better-auth": "catalog:",
|
||||||
"nanoid": "5.1.5",
|
"nanoid": "catalog:",
|
||||||
"zx": "7.2.3"
|
"zod": "catalog:",
|
||||||
|
"zx": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ import { defineConfig } from 'tsup'
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
clean: true,
|
clean: true,
|
||||||
target: 'es2020',
|
target: 'es2020',
|
||||||
entry: ['index.ts', 'auth.ts'],
|
entry: ['index.ts', 'auth.ts', 'zod.ts'],
|
||||||
dts: true,
|
dts: true,
|
||||||
external: ['mongodb'],
|
external: ['mongodb'],
|
||||||
format: ['cjs'],
|
format: ['cjs'],
|
||||||
|
|||||||
1
packages/compiled/zod.ts
Normal file
1
packages/compiled/zod.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './node_modules/zod'
|
||||||
1452
pnpm-lock.yaml
generated
1452
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,136 @@
|
|||||||
packages:
|
packages:
|
||||||
- packages/*
|
- packages/*
|
||||||
- apps/*
|
- apps/*
|
||||||
|
catalog:
|
||||||
|
'@algolia/client-search': ^4.22.1
|
||||||
|
'@antfu/install-pkg': 1.0.0
|
||||||
|
'@aws-sdk/client-s3': 3.802.0
|
||||||
|
'@babel/core': 7.27.1
|
||||||
|
'@babel/plugin-transform-modules-commonjs': 7.27.1
|
||||||
|
'@babel/plugin-transform-typescript': 7.27.1
|
||||||
|
'@babel/types': ^7.27.1
|
||||||
|
'@fastify/cookie': 11.0.2
|
||||||
|
'@fastify/multipart': 9.0.3
|
||||||
|
'@fastify/static': 8.1.1
|
||||||
|
'@innei/next-async': 0.3.0
|
||||||
|
'@innei/prettier': 0.15.0
|
||||||
|
'@innei/pretty-logger-nestjs': 0.3.3
|
||||||
|
'@keyv/redis': 4.4.0
|
||||||
|
'@langchain/core': 0.3.51
|
||||||
|
'@langchain/openai': 0.5.10
|
||||||
|
'@modelcontextprotocol/sdk': 1.11.0
|
||||||
|
'@nestjs/cache-manager': 3.0.1
|
||||||
|
'@nestjs/cli': 11.0.7
|
||||||
|
'@nestjs/common': 11.1.0
|
||||||
|
'@nestjs/core': 11.1.0
|
||||||
|
'@nestjs/event-emitter': 3.0.1
|
||||||
|
'@nestjs/mapped-types': ^2.1.0
|
||||||
|
'@nestjs/platform-fastify': 11.1.0
|
||||||
|
'@nestjs/platform-socket.io': 11.1.0
|
||||||
|
'@nestjs/schedule': 6.0.0
|
||||||
|
'@nestjs/schematics': 11.0.5
|
||||||
|
'@nestjs/testing': 11.1.0
|
||||||
|
'@nestjs/throttler': 6.4.0
|
||||||
|
'@nestjs/websockets': 11.1.0
|
||||||
|
'@simplewebauthn/server': 10.0.1
|
||||||
|
'@socket.io/redis-adapter': 8.3.0
|
||||||
|
'@socket.io/redis-emitter': 5.1.0
|
||||||
|
'@swc/core': 1.11.24
|
||||||
|
'@sxzz/eslint-config': 6.1.1
|
||||||
|
'@typegoose/auto-increment': 4.13.0
|
||||||
|
'@typegoose/typegoose': 12.15.0
|
||||||
|
'@types/babel__core': 7.20.5
|
||||||
|
'@types/bcryptjs': ^3.0.0
|
||||||
|
'@types/cls-hooked': ^4.3.9
|
||||||
|
'@types/ejs': 3.1.5
|
||||||
|
'@types/get-image-colors': 4.0.5
|
||||||
|
'@types/js-yaml': 4.0.9
|
||||||
|
'@types/jsonwebtoken': 9.0.9
|
||||||
|
'@types/lodash': 4.17.16
|
||||||
|
'@types/mime-types': 2.1.4
|
||||||
|
'@types/mongoose-aggregate-paginate-v2': 1.0.12
|
||||||
|
'@types/node': 22.15.3
|
||||||
|
'@types/nodemailer': 6.4.17
|
||||||
|
'@types/qs': 6.9.18
|
||||||
|
'@types/remove-markdown': 0.3.4
|
||||||
|
'@types/semver': 7.7.0
|
||||||
|
'@types/ua-parser-js': 0.7.39
|
||||||
|
'@types/validator': 13.15.0
|
||||||
|
'@vercel/ncc': 0.38.3
|
||||||
|
algoliasearch: 4.24.0
|
||||||
|
axios: ^1.9.0
|
||||||
|
axios-retry: 4.5.0
|
||||||
|
bcryptjs: ^3.0.2
|
||||||
|
better-auth: 1.2.5
|
||||||
|
blurhash: 2.0.5
|
||||||
|
cache-manager: 6.4.2
|
||||||
|
class-transformer: 0.5.1
|
||||||
|
class-validator: 0.13.2
|
||||||
|
class-validator-jsonschema: npm:@innei/class-validator-jsonschema@3.1.2
|
||||||
|
cls-hooked: ^4.2.2
|
||||||
|
commander: 13.1.0
|
||||||
|
cron: ^3.5.0
|
||||||
|
cross-env: 7.0.3
|
||||||
|
dayjs: 1.11.13
|
||||||
|
ejs: 3.1.10
|
||||||
|
eslint: ^9.24.0
|
||||||
|
form-data: 4.0.2
|
||||||
|
inquirer: ^10.2.2
|
||||||
|
ioredis: 5.6.1
|
||||||
|
isbot: 5.1.27
|
||||||
|
js-yaml: ^4.1.0
|
||||||
|
json5: 2.2.3
|
||||||
|
jsonwebtoken: 9.0.2
|
||||||
|
jszip: 3.10.1
|
||||||
|
keyv: 5.3.3
|
||||||
|
langchain: 0.3.24
|
||||||
|
linkedom: 0.18.10
|
||||||
|
lint-staged: 15.5.0
|
||||||
|
lodash: ^4.17.21
|
||||||
|
lru-cache: 11.1.0
|
||||||
|
marked: 15.0.11
|
||||||
|
mime-types: ^3.0.1
|
||||||
|
mkdirp: ^3.0.1
|
||||||
|
mongoose: 8.14.1
|
||||||
|
mongoose-aggregate-paginate-v2: 1.1.4
|
||||||
|
mongoose-autopopulate: 1.1.0
|
||||||
|
mongoose-lean-getters: 2.2.1
|
||||||
|
mongoose-lean-virtuals: 1.1.0
|
||||||
|
mongoose-paginate-v2: 1.9.0
|
||||||
|
nanoid: 5.1.5
|
||||||
|
node-machine-id: 1.1.12
|
||||||
|
nodemailer: 7.0.0
|
||||||
|
openai: 4.97.0
|
||||||
|
pluralize: ^8.0.0
|
||||||
|
prettier: 3.5.3
|
||||||
|
qs: 6.14.0
|
||||||
|
reflect-metadata: 0.2.2
|
||||||
|
remove-markdown: 0.6.2
|
||||||
|
remove-md-codeblock: 0.0.4
|
||||||
|
rimraf: 6.0.1
|
||||||
|
rxjs: 7.8.2
|
||||||
|
semver: 7.7.1
|
||||||
|
sharp: 0.34.1
|
||||||
|
simple-git-hooks: 2.12.1
|
||||||
|
slugify: 1.6.6
|
||||||
|
snakecase-keys: 6.0.0
|
||||||
|
socket.io: ^4.8.1
|
||||||
|
source-map-support: ^0.5.21
|
||||||
|
ts-node: 10.9.2
|
||||||
|
tsconfig-paths: 4.2.0
|
||||||
|
tsup: 8.4.0
|
||||||
|
typescript: 5.8.3
|
||||||
|
ua-parser-js: 2.0.3
|
||||||
|
unplugin-swc: 1.5.2
|
||||||
|
vite: 5.4.10
|
||||||
|
vite-tsconfig-paths: 5.1.4
|
||||||
|
vitest: 1.5.2
|
||||||
|
vm2: 3.9.19
|
||||||
|
wildcard-match: 5.1.4
|
||||||
|
xss: 1.0.15
|
||||||
|
zod: 3.24.3
|
||||||
|
zx: 7.2.3
|
||||||
|
zx-cjs: 7.0.7-0
|
||||||
|
catalogs:
|
||||||
|
conflicts_@types/node_22_14_0:
|
||||||
|
'@types/node': 22.14.0
|
||||||
|
|||||||
Reference in New Issue
Block a user