目录

一、思路

二、准备环境

三、AI助手模块实现

四、聊天模块实现

五、jwt处理模块(后台管理员登录准备)

六、管理员登录模块

七、实体类

八、将各模块汇总


一、思路

分为ai模块、聊天模块、如果有登录系统就在加入jwt,管理员等,源码在:AI-customer/ai-customer-service-backend at master · BI-shi-qiang/AI-customer

二、准备环境

node20+、mongodb8、本地安装@nestjs、提前注册deepsee开放平台获取api、还有项目中所用到的一些依赖如下

(1)package.json

{
  "name": "ai-customer-service-backend",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "private": true,
  "license": "UNLICENSED",
  "scripts": {
    "build": "nest build",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
    "start": "nest start",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main",
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },
  "dependencies": {
    "@langchain/core": "^1.1.39",
    "@langchain/openai": "^1.4.2",
    "@nestjs/common": "^11.0.1",
    "@nestjs/config": "^4.0.3",
    "@nestjs/core": "^11.0.1",
    "@nestjs/jwt": "^11.0.2",
    "@nestjs/mongoose": "^11.0.4",
    "@nestjs/passport": "^11.0.5",
    "@nestjs/platform-express": "^11.0.1",
    "@nestjs/platform-socket.io": "^11.1.18",
    "@nestjs/websockets": "^11.1.18",
    "bcryptjs": "^3.0.3",
    "cors": "^2.8.6",
    "langchain": "^1.3.0",
    "mongoose": "^9.4.1",
    "passport": "^0.7.0",
    "passport-jwt": "^4.0.1",
    "reflect-metadata": "^0.2.2",
    "rxjs": "^7.8.1",
    "socket.io": "^4.8.3"
  },
  "devDependencies": {
    "@eslint/eslintrc": "^3.2.0",
    "@eslint/js": "^9.18.0",
    "@nestjs/cli": "^11.0.0",
    "@nestjs/schematics": "^11.0.0",
    "@nestjs/testing": "^11.0.1",
    "@types/bcryptjs": "^3.0.0",
    "@types/express": "^5.0.0",
    "@types/jest": "^30.0.0",
    "@types/node": "^22.10.7",
    "@types/passport-jwt": "^4.0.1",
    "@types/supertest": "^6.0.2",
    "eslint": "^9.18.0",
    "eslint-config-prettier": "^10.0.1",
    "eslint-plugin-prettier": "^5.2.2",
    "globals": "^16.0.0",
    "jest": "^30.0.0",
    "prettier": "^3.4.2",
    "source-map-support": "^0.5.21",
    "supertest": "^7.0.0",
    "ts-jest": "^29.2.5",
    "ts-loader": "^9.5.2",
    "ts-node": "^10.9.2",
    "tsconfig-paths": "^4.2.0",
    "typescript": "^5.7.3",
    "typescript-eslint": "^8.20.0"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".*\\.spec\\.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "collectCoverageFrom": [
      "**/*.(t|j)s"
    ],
    "coverageDirectory": "../coverage",
    "testEnvironment": "node"
  }
}

(2).env

# 端口
PORT=3000

# MongoDB 8.0
MONGODB_URI=mongodb://localhost:27017/~

# DeepSeek API
DEEPSEEK_API_KEY=~
DEEPSEEK_API_URL=https://api.deepseek.com/v1
DEEPSEEK_MODEL=deepseek-chat

# CORS
CORS_ORIGIN=http://localhost:5173,http://localhost:8080

# JWT
JWT_SECRET=~

三、AI助手模块实现

(1)src/ai/ai.service.ts主要是利用langchain框架导入大模型,便于多模型切换

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { ChatOpenAI } from '@langchain/openai';

@Injectable()
export class AiService {
  private llm: ChatOpenAI;

  constructor(private readonly configService: ConfigService) {
    const apiKey = this.configService.get<string>('DEEPSEEK_API_KEY')!;
    const baseURL = this.configService.get<string>('DEEPSEEK_API_URL')!;
    const model = this.configService.get<string>('DEEPSEEK_MODEL')!;

    this.llm = new ChatOpenAI({
      apiKey,
      model,
      streaming: true,
      temperature: 0.7,
      maxTokens: 1024,
      configuration: { baseURL },
    });
  }

  async streamChat(message: string) {
    return this.llm.stream([['user', message]]);
  }
}

(2)src/ai/gaiban.ts

export const MY_GAIBAN = {
  // ...你原来的内容
  lifeFullStory: `
    给这个ai的知识库,让他知道你的产品是干啥的,常问的问题让ai能够根据知识库内容回答
`,
  answerRulesFull: `
1. 回话要求那些,比如以什么风格回复,那些不能说等
2.
3.
`,
};

(3)src/ai/ai.module.ts将这个ai模块导出

import { Module } from '@nestjs/common';
import { AiService } from './ai.service';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [ConfigModule],
  providers: [AiService],
  exports: [AiService],
})
export class AiModule {}

四、聊天模块实现

(1)src/chat/chat.service.ts

聊天的主要逻辑部分,就是ai回复功能,人工聊天功能,聊天内容存数据库等

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Chat, ChatDocument } from '../schemas/chat.schema';
import { AiService } from '../ai/ai.service';
import { MY_GAIBAN } from '../ai/gaiban';
import { PromptTemplate } from '@langchain/core/prompts';
import { Observable } from 'rxjs';
import { ChatGateway } from './chat.gateway';

import {
  HumanSession,
  HumanSessionDocument,
} from '../schemas/human-session.schema';

const EMOJI_MAP = {
  哈哈哈哈哈: '🤣',
  牛批: '👍',
  没得问题: '👌',
  懂嘞: '👌',
  莫为难: '🙏',
  劳资: '🤬',
  嘿嘿嘿: '😃',
};

@Injectable()
export class ChatService {
  private readonly ASSISTANT_PROMPT = PromptTemplate.fromTemplate(`
你是~。
说话风格:搞笑、耿直、有点皮、口语化,带口头禅~。

以下是你的所有资料,必须严格按照这个回答,不准瞎编:
{knowledge}

规则:
1. 问什么答什么,简短自然,控制在3~5句话以内,尽量用谦虚的语气回答,不要自以为是。
2. 可以轻松闲聊,但不懂就说不懂
3. 不准输出模板、不准解释规则、不准加括号、可以加括号描述下内心的调皮想法,但不过分
4. 自我介绍:可以用这个:hello,~,;也不要一直都是这句话开头,可时不时修改一下,就是保持自然度
5. 不懂就说:哎呀,我的Token是不是不要钱,这些问题国人跑去问豆包~~
6. 自然聊天,不频繁提网站
7. 表情包不要多用,一句话最多加1个,偶尔才用,不要每个词都加
~

聊天历史:
{history}

用户现在问:
{input}
`);

  constructor(
    @InjectModel(Chat.name) private chatModel: Model<ChatDocument>,
    @InjectModel(HumanSession.name)
    private humanSessionModel: Model<HumanSessionDocument>,
    private aiService: AiService,
    private readonly chatGateway: ChatGateway,
  ) {}

  // ====================== 核心:用户发消息(自动判断 AI / 人工)======================
  streamMessage(sessionId: string, message: string): Observable<string> {
    return new Observable((subscriber) => {
      void (async () => {
        try {
          const session = await this.getOrCreateSession(sessionId);

          // ============== 人工模式:不调用AI,只存消息,等后台回复 ==============
          if (session.status === 'human') {
            const newMsg = await this.saveHistory(
              sessionId,
              message,
              '',
              false,
            );
            this.chatGateway.sendMessageToSession(sessionId, newMsg);
            setTimeout(() => {
              subscriber.next('');
              subscriber.complete();
            }, 100);
            return;
          }

          // ============== AI 模式:正常流式回复 ==============
          const historyDocs = await this.getHistory(sessionId);
          const history = historyDocs
            .map(
              (item) => `用户:${item.userMessage}\n阿毕:${item.aiResponse}`,
            )
            .join('\n');

          const safeKnowledge = JSON.stringify(MY_GAIBAN, null, 2) //MY_PERSONAL_PROFILE
            .replace(/{/g, '【')
            .replace(/}/g, '】');

          const prompt = await this.ASSISTANT_PROMPT.format({
            knowledge: safeKnowledge,
            history,
            input: message,
          });

          const stream = await this.aiService.streamChat(prompt);
          let fullAIResponse = '';

          for await (const chunk of stream) {
            if (typeof chunk.content === 'string') {
              const token = chunk.content;
              fullAIResponse += token;
              subscriber.next(token);
            }
          }

          let finalText = fullAIResponse;
          const keys = Object.keys(EMOJI_MAP);
          const hasKeyword = keys.some((k) => finalText.includes(k));

          if (hasKeyword && Math.random() > 0.5) {
            for (const k of keys) {
              if (finalText.includes(k)) {
                finalText = finalText.replace(k, `${k}${EMOJI_MAP[k]}`);
                break;
              }
            }
          }

          subscriber.next('\n' + finalText.slice(fullAIResponse.length));
          // 保存并推送
          const newMessage = await this.saveHistory(
            sessionId,
            message,
            finalText,
            false,
          );
          // 👇 实时推送
          this.chatGateway.sendMessageToSession(sessionId, newMessage);
          subscriber.complete();
        } catch (err) {
          console.error('聊天错误:', err);
          subscriber.error(err);
        }
      })();
    });
  }

  // ====================== 管理员:人工发送消息 ======================
  async humanSendMessage(sessionId: string, adminId: string, content: string) {
    const newMessage = await this.saveHistory(sessionId, '', content, true);
    // 👇 实时推送
    this.chatGateway.sendMessageToSession(sessionId, newMessage);
    return { success: true, content };
  }

  // ====================== 用户:人工发送消息 ======================
  async humanUserMessage(sessionId: string, message: string) {
    const newMsg = await this.saveHistory(
      sessionId,
      message, // 用户消息
      '', // 回复为空
      false,
    );
    try {
      // 包裹 try/catch,永远不会 500
      this.chatGateway.sendMessageToSession(sessionId, newMsg);
    } catch (err) {
      console.error('发送人工消息错误:', err);
    }
    return newMsg;
  }
  // ====================== 切换到人工 ======================
  async switchToHuman(sessionId: string, adminId?: string) {
    await this.humanSessionModel.findOneAndUpdate(
      { sessionId },
      { status: 'human', adminId },
      { upsert: true },
    );
    return { success: true, msg: '已切换为人工服务' };
  }

  // ====================== 切换回AI ======================
  async switchToAi(sessionId: string) {
    await this.humanSessionModel.findOneAndUpdate(
      { sessionId },
      { status: 'ai', adminId: null },
      { upsert: true },
    );
    return { success: true, msg: '已切换回AI助手' };
  }

  // ====================== 获取会话状态 ======================
  async getSessionStatus(sessionId: string) {
    const s = await this.getOrCreateSession(sessionId);
    return { status: s.status, adminId: s.adminId };
  }

  // ====================== 工具方法 ======================
  private async getOrCreateSession(sessionId: string) {
    let s = await this.humanSessionModel.findOne({ sessionId });
    if (!s) s = await this.humanSessionModel.create({ sessionId });
    return s;
  }

  async saveHistory(
    sessionId: string,
    userMessage: string,
    aiResponse: string,
    isHuman = false,
  ) {
    return this.chatModel.create({
      sessionId,
      userMessage,
      aiResponse,
      isHuman,
    });
  }

  async getHistory(sessionId: string) {
    return this.chatModel.find({ sessionId }).sort({ createdAt: 1 });
  }

  async deleteSession(sessionId: string) {
    await this.chatModel.deleteMany({ sessionId });
    await this.humanSessionModel.deleteOne({ sessionId });
    return { success: true };
  }

  // 会话列表
  getAllSessions() {
    return this.chatModel.aggregate([
      {
        $group: {
          _id: '$sessionId',
          lastMsg: { $last: '$userMessage' },
          time: { $max: '$createdAt' },
        },
      },
      { $project: { sessionId: '$_id', lastMsg: 1, time: 1 } },
      { $sort: { time: -1 } },
    ]);
  }

  // 所有人工会话
  getHumanSessions() {
    return this.humanSessionModel.find({ status: 'human' }).populate('adminId');
  }
}

(2)src/chat/chat.gateway.ts处理聊天过程中实时聊天的处理,运用websockets

import {
  WebSocketGateway,
  WebSocketServer,
  SubscribeMessage,
  OnGatewayConnection,
  OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';

@WebSocketGateway({
  cors: {
    origin: true,
    credentials: true,
  },
})
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
  @WebSocketServer()
  server: Server;

  handleConnection(client: Socket) {
    console.log('✅ 客户端已连接:', client.id);
  }

  handleDisconnect(client: Socket) {
    console.log('❌ 客户端已断开:', client.id);
  }

  @SubscribeMessage('joinSession')
  async handleJoinSession(client: Socket, sessionId: string) {
    // 👈 加 async
    try {
      await client.join(sessionId); // 👈 加 await
      console.log('📩 加入会话:', sessionId);
    } catch (err) {
      console.error('加入房间失败:', err);
    }
  }

  // 推送新消息到会话
  sendMessageToSession(sessionId: string, message: any) {
    this.server.to(sessionId).emit('newMessage', message);
  }
}

(3)src/chat/chat.controller.ts将聊天功能封装成接口便于前端调用

import {
  Controller,
  Get,
  Delete,
  Param,
  Query,
  Res,
  UseGuards,
  Post,
  Body,
  Request,
} from '@nestjs/common';
import { ChatService } from './chat.service';
import type { Response } from 'express';
import { JwtGuard } from '../auth/jwt.guard';

interface UserPayload {
  id: string;
  username: string;
}

@Controller('chat')
export class ChatController {
  constructor(private chatService: ChatService) {}

  // 用户聊天流
  @Get('stream')
  stream(
    @Query('sessionId') sessionId: string,
    @Query('message') message: string,
    @Res() res: Response,
  ) {
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    res.setHeader('Access-Control-Allow-Origin', '*');

    this.chatService.streamMessage(sessionId, message).subscribe({
      next: (token) => res.write(`data: ${token}\n\n`),
      complete: () => {
        res.write('data: [DONE]\n\n');
        res.end();
      },
      error: () => res.end(),
    });
  }

  // ====================== 【用户】请求转人工 ======================
  @Get('request-human')
  async requestHuman(@Query('sessionId') sessionId: string) {
    return this.chatService.switchToHuman(sessionId);
  }

  // ====================== 【管理员】登录后可用 ======================
  @UseGuards(JwtGuard)
  @Post('human-send')
  humanSend(
    @Body('sessionId') sessionId: string,
    @Body('content') content: string,
    @Request() req: { user: UserPayload },
  ) {
    return this.chatService.humanSendMessage(sessionId, req.user.id, content);
  }

  // ====================== 【用户】人工发送消息 ======================
  @Post('user-send-message')
  async userSendMessage(@Body() body: { sessionId: string; message: string }) {
    return this.chatService.humanUserMessage(body.sessionId, body.message);
  }
  // 会话状态
  @Get('session-status/:sessionId')
  async getSessionStatus(@Param('sessionId') sessionId: string) {
    return this.chatService.getSessionStatus(sessionId);
  }

  // @UseGuards(JwtGuard)
  @Get('switch-human/:sessionId')
  switchToHuman(
    @Param('sessionId') sessionId: string,
    // @Request() req: { user: UserPayload },
  ) {
    return this.chatService.switchToHuman(sessionId);
  }

  // @UseGuards(JwtGuard)
  @Get('switch-ai/:sessionId')
  switchToAi(@Param('sessionId') sessionId: string) {
    return this.chatService.switchToAi(sessionId);
  }

  @UseGuards(JwtGuard)
  @Get('human-sessions')
  getHumanSessions() {
    return this.chatService.getHumanSessions();
  }

  // 原有接口
  @Get('history/:sessionId')
  getHistory(@Param('sessionId') sessionId: string) {
    return this.chatService.getHistory(sessionId);
  }

  @Delete('delete/:sessionId')
  deleteSession(@Param('sessionId') sessionId: string) {
    return this.chatService.deleteSession(sessionId);
  }

  @Get('sessions')
  getAllSessions() {
    return this.chatService.getAllSessions();
  }

  @Get('status/:sessionId')
  getStatus(@Param('sessionId') sessionId: string) {
    return this.chatService.getSessionStatus(sessionId);
  }
}

(4)src/chat/chat.module.ts将聊天模块导出

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { ChatService } from './chat.service';
import { ChatController } from './chat.controller';
import { Chat, ChatSchema } from '../schemas/chat.schema';
import { AiModule } from '../ai/ai.module';
import { ChatGateway } from './chat.gateway';
import {
  HumanSession,
  HumanSessionSchema,
} from '../schemas/human-session.schema';

@Module({
  imports: [
    MongooseModule.forFeature([
      { name: Chat.name, schema: ChatSchema },
      { name: HumanSession.name, schema: HumanSessionSchema },
    ]),
    AiModule,
  ],
  controllers: [ChatController],
  providers: [ChatService, ChatGateway],
  exports: [ChatGateway],
})
export class ChatModule {}

五、jwt处理模块(后台管理员登录准备)

(1)arc/auth/jwt.strategy.ts

import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly configService: ConfigService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: configService.get('JWT_SECRET') || 'bsq_ai_secret',
      ignoreExpiration: false,
      passReqToCallback: false,
    });
  }

  validate(payload: { sub: string; username: string }) {
    return {
      id: payload.sub,
      username: payload.username,
    };
  }
}

(2)src/auth/jwt.guard.ts

import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtGuard extends AuthGuard('jwt') {}

(3)src/auth/auth.module.ts将此模块导出

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './jwt.strategy';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [
    PassportModule,
    JwtModule.registerAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
        secret: configService.get('JWT_SECRET', 'bsq_ai_secret'),
        signOptions: { expiresIn: '7d' },
      }),
      inject: [ConfigService],
    }),
  ],
  providers: [JwtStrategy],
  exports: [JwtModule],
})
export class AuthModule {}

六、管理员登录模块

因为这个聊天系统就是任何用户都可以用,所以就只有管理员登录后台查看回复一下这个,就只做了后台管理员的登录

(1)src/admin/dto/login.dto.ts

export class LoginDto {
  username: string;
  password: string;
}

(2)src/admin/admin.service.ts

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import * as bcrypt from 'bcryptjs';
import { Admin, AdminDocument } from '../schemas/admin.schema';
import { LoginDto } from './dto/login.dto';

@Injectable()
export class AdminService {
  constructor(
    @InjectModel(Admin.name) private adminModel: Model<AdminDocument>,
    private jwtService: JwtService,
  ) {}

  // 登录
  async login(loginDto: LoginDto) {
    const { username, password } = loginDto;
    const admin = await this.adminModel.findOne({ username });

    if (!admin) throw new UnauthorizedException('账号不存在');

    const isMatch = await bcrypt.compare(password, admin.password);
    if (!isMatch) throw new UnauthorizedException('密码错误');

    const token = this.jwtService.sign({
      sub: admin._id.toString(), // 转字符串,避免类型问题
      username: admin.username,
    });

    return {
      admin: { id: admin._id.toString(), username: admin.username },
      token,
    };
  }

  // 初始化超级管理员(第一次运行自动创建)
  async initAdmin() {
    const exist = await this.adminModel.findOne({ username: 'admin' });
    if (!exist) {
      const hash = await bcrypt.hash('123456', 10);
      await this.adminModel.create({ username: 'admin', password: hash });
      console.log('✅ 初始管理员创建成功:admin / 123456');
    }
  }
}

(3)src/admin/admin.controller.ts

import { Controller, Post, Body } from '@nestjs/common';
import { AdminService } from './admin.service';
import { LoginDto } from './dto/login.dto';

@Controller('admin')
export class AdminController {
  constructor(private readonly adminService: AdminService) {}

  @Post('login')
  login(@Body() loginDto: LoginDto) {
    return this.adminService.login(loginDto);
  }
}

(4)src/admin/admin.module.ts将此模块导出

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { AdminService } from './admin.service';
import { AdminController } from './admin.controller';
import { Admin, AdminSchema } from '../schemas/admin.schema';
import { AuthModule } from '../auth/auth.module';

@Module({
  imports: [
    MongooseModule.forFeature([{ name: Admin.name, schema: AdminSchema }]),
    AuthModule,
  ],
  controllers: [AdminController],
  providers: [AdminService],
  exports: [AdminService],
})
export class AdminModule {}

七、实体类

(1)src/schemas/chat.schema.ts聊天表

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type ChatDocument = Chat & Document;

@Schema({ timestamps: true })
export class Chat {
  @Prop({ required: true })
  sessionId: string;

  @Prop({ required: false })
  userMessage: string;

  @Prop({ required: false })
  aiResponse: string;
  // 新增:是否人工回复
  @Prop({ default: false })
  isHuman: boolean;
}
export const ChatSchema = SchemaFactory.createForClass(Chat);

(2)src/schemas/admin.schema.ts管理员

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type AdminDocument = Admin & Document;

@Schema({ timestamps: true })
export class Admin {
  @Prop({ required: true, unique: true })
  username: string;

  @Prop({ required: true })
  password: string;
}

export const AdminSchema = SchemaFactory.createForClass(Admin);

(3)src/schemas/human-session.schema.ts

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type HumanSessionDocument = HumanSession & Document;

@Schema({ timestamps: true })
export class HumanSession {
  @Prop({ required: true, unique: true })
  sessionId: string;

  // 状态:ai / human
  @Prop({ default: 'ai' })
  status: 'ai' | 'human';

  // 当前接待的管理员ID
  @Prop({ default: null })
  adminId: string;
}

export const HumanSessionSchema = SchemaFactory.createForClass(HumanSession);

八、将各模块汇总

(1)src/app.module.ts

import { Module, OnModuleInit } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { ConfigModule } from '@nestjs/config';
import { ChatModule } from './chat/chat.module';
import { AiModule } from './ai/ai.module';
import { AdminModule } from './admin/admin.module';
import { AuthModule } from './auth/auth.module';
import { AdminService } from './admin/admin.service';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true, envFilePath: '.env' }),
    MongooseModule.forRoot(process.env.MONGODB_URI!),
    AuthModule,
    AdminModule,
    ChatModule,
    AiModule,
  ],
})
export class AppModule implements OnModuleInit {
  constructor(private adminService: AdminService) {}

  async onModuleInit() {
    await this.adminService.initAdmin();
  }
}

(2)main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.enableCors();
  await app.listen(process.env.PORT ?? 3000);
}
bootstrap();

最后npm run start:dev运行

至此!一个简易的ai助手完成

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐