feat(ai): 添加 AI 服务适配器管理器和新接口
- 新增 AiAdapterManager 类,用于管理和初始化不同 AI 服务适配器 - 添加 AiServiceAdapter 接口和两个实现类:DeepSeekAdapter 和 TongyiAdapter - 在 AiConfig 实体中增加 provider 字段,用于标识 AI 服务提供商 - 新增 ai-config 模块,负责 AI 配置的管理和存储 - 在 ai 服务中集成适配器管理器,支持动态获取不同 AI 服务的适配器 - 更新 ai 控制器,添加获取适配器信息的接口
This commit is contained in:
parent
ae7c88d213
commit
6473395f86
|
@ -6,3 +6,4 @@
|
|||
1. 语言:TypeScript
|
||||
2. nodejs 使用版本v22
|
||||
3. 执行node, npm 相关命令时先执行`nvm use v22`切换到v22版本
|
||||
4. dev环境运行命令是`npm run dev`
|
|
@ -0,0 +1,38 @@
|
|||
import { AiConfig } from './ai-config.entity';
|
||||
import { AiServiceAdapter } from './ai.adapter';
|
||||
import { DeepSeekAdapter } from './deepseek.adapter';
|
||||
import { TongyiAdapter } from './tongyi.adapter';
|
||||
|
||||
export class AiAdapterManager {
|
||||
private adapters: Map<string, AiServiceAdapter> = new Map();
|
||||
|
||||
constructor(private readonly aiConfigs: AiConfig[]) {
|
||||
this.initializeAdapters();
|
||||
}
|
||||
|
||||
private initializeAdapters() {
|
||||
this.aiConfigs?.forEach(config => {
|
||||
// 确保config.id是字符串类型
|
||||
const serviceId = config.id.toString();
|
||||
|
||||
switch (config.provider) {
|
||||
case 'deepseek':
|
||||
this.adapters.set(serviceId, new DeepSeekAdapter(config));
|
||||
break;
|
||||
case 'tongyi':
|
||||
this.adapters.set(serviceId, new TongyiAdapter(config));
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported AI provider: ${config.provider}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getAdapter(serviceId: string): AiServiceAdapter {
|
||||
const adapter = this.adapters.get(serviceId);
|
||||
if (!adapter) {
|
||||
throw new Error(`AI adapter not found for service ID: ${serviceId}`);
|
||||
}
|
||||
return adapter;
|
||||
}
|
||||
}
|
|
@ -12,6 +12,10 @@ export class AiConfig {
|
|||
@Column()
|
||||
apiKey!: string;
|
||||
|
||||
// 新增provider字段,用于标识AI服务提供商
|
||||
@Column({ type: 'enum', enum: ['deepseek', 'tongyi'] })
|
||||
provider!: 'deepseek' | 'tongyi';
|
||||
|
||||
@OneToOne(() => Workspace)
|
||||
@JoinColumn()
|
||||
workspace!: Workspace;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { AiConfigService } from './ai-config.service';
|
||||
import { AiConfigController } from './ai-config.controller';
|
||||
import { WorkspaceModule } from '../workspace/workspace.module';
|
||||
import { AiConfigRepository } from './ai-config.repository';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { AiConfig } from './ai-config.entity';
|
||||
import { WorkspaceRepository } from '../workspace/workspace.repository';
|
||||
import { JwtStrategy } from '@src/auth';
|
||||
|
||||
@Module({
|
||||
imports: [WorkspaceModule, TypeOrmModule.forFeature([AiConfig])],
|
||||
providers: [
|
||||
AiConfigService,
|
||||
AiConfigRepository,
|
||||
WorkspaceRepository,
|
||||
JwtStrategy
|
||||
],
|
||||
controllers: [AiConfigController],
|
||||
exports: [AiConfigService]
|
||||
})
|
||||
export class AiConfigModule {}
|
|
@ -0,0 +1,34 @@
|
|||
import { AiConfig } from "./ai-config.entity";
|
||||
|
||||
export interface AiServiceAdapter {
|
||||
generateText(model: string, prompt: string, config?: Record<string, any>): Promise<string>;
|
||||
chat(model: string, messages: Array<{role: string, content: string}>, config?: Record<string, any>): Promise<string>;
|
||||
}
|
||||
|
||||
export class DeepSeekAdapter implements AiServiceAdapter {
|
||||
constructor(private readonly config: AiConfig) {}
|
||||
|
||||
async generateText(model: string, prompt: string): Promise<string> {
|
||||
// 实现DeepSeek的文本生成逻辑
|
||||
return `Generated text by ${model}: ${prompt}`;
|
||||
}
|
||||
|
||||
async chat(model: string, messages: Array<{role: string, content: string}>): Promise<string> {
|
||||
// 实现DeepSeek的对话交互逻辑
|
||||
return `Chat response from ${model}: ${JSON.stringify(messages)}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class TongyiAdapter implements AiServiceAdapter {
|
||||
constructor(private readonly config: AiConfig) {}
|
||||
|
||||
async generateText(model: string, prompt: string): Promise<string> {
|
||||
// 实现通义千问的文本生成逻辑
|
||||
return `Tongyi generated text: ${prompt}`;
|
||||
}
|
||||
|
||||
async chat(model: string, messages: Array<{role: string, content: string}>): Promise<string> {
|
||||
// 实现通义千问的对话交互逻辑
|
||||
return `Tongyi chat response: ${JSON.stringify(messages)}`;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { Controller, Post, Body, UseGuards } from '@nestjs/common';
|
||||
import { Controller, Post, Body, UseGuards, Get, Param } from '@nestjs/common';
|
||||
import { AiService } from './ai.service';
|
||||
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||
|
||||
|
@ -11,4 +11,10 @@ export class AiController {
|
|||
generateCode(@Body() body: { prompt: string; workspaceId: number }) {
|
||||
return this.aiService.generateCode(body.prompt, body.workspaceId);
|
||||
}
|
||||
|
||||
@Get('adapter/:serviceId')
|
||||
getAdapterInfo(@Param('serviceId') serviceId: string) {
|
||||
const adapter = this.aiService.getAdapter(serviceId);
|
||||
return { provider: adapter.constructor.name };
|
||||
}
|
||||
}
|
|
@ -1,22 +1,15 @@
|
|||
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AiConfigService } from './ai-config.service';
|
||||
import { AiConfigController } from './ai-config.controller';
|
||||
import { WorkspaceModule } from '../workspace/workspace.module';
|
||||
import { AiConfigRepository } from './ai-config.repository';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { AiConfig } from './ai-config.entity';
|
||||
import { WorkspaceRepository } from '../workspace/workspace.repository'; // 新增导入
|
||||
import { JwtStrategy } from '@src/auth';
|
||||
import { AiService } from './ai.service';
|
||||
import { AiController } from './ai.controller';
|
||||
import { AiAdapterManager } from './ai-adapter.manager';
|
||||
|
||||
@Module({
|
||||
imports: [WorkspaceModule, TypeOrmModule.forFeature([AiConfig])],
|
||||
providers: [
|
||||
AiConfigService,
|
||||
AiConfigRepository,
|
||||
WorkspaceRepository, // 添加缺失的依赖
|
||||
JwtStrategy
|
||||
],
|
||||
controllers: [AiConfigController],
|
||||
exports: [AiConfigService]
|
||||
imports: [TypeOrmModule.forFeature([AiConfig])],
|
||||
providers: [AiService, AiAdapterManager],
|
||||
controllers: [AiController],
|
||||
exports: [AiService]
|
||||
})
|
||||
export class AiModule {}
|
|
@ -2,19 +2,38 @@ import { Injectable } from '@nestjs/common';
|
|||
import { HttpService } from '@nestjs/axios';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { AiConfigService } from './ai-config.service';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { AiConfig } from './ai-config.entity';
|
||||
import { AiAdapterManager } from './ai-adapter.manager';
|
||||
|
||||
@Injectable()
|
||||
export class AiService {
|
||||
private readonly defaultModel: string;
|
||||
private adapterManager!: AiAdapterManager;
|
||||
|
||||
constructor(
|
||||
private readonly httpService: HttpService,
|
||||
private readonly configService: ConfigService,
|
||||
private readonly aiConfigService: AiConfigService,
|
||||
@InjectRepository(AiConfig)
|
||||
private aiConfigRepository: Repository<AiConfig>,
|
||||
) {
|
||||
this.defaultModel = this.configService.get<string>('AI_DEFAULT_MODEL', 'gpt-3.5-turbo');
|
||||
}
|
||||
|
||||
async initializeAdapterManager() {
|
||||
const configs = await this.aiConfigRepository.find();
|
||||
this.adapterManager = new AiAdapterManager(configs);
|
||||
}
|
||||
|
||||
getAdapter(serviceId: string) {
|
||||
if (!this.adapterManager) {
|
||||
throw new Error('AI adapter manager not initialized');
|
||||
}
|
||||
return this.adapterManager.getAdapter(serviceId);
|
||||
}
|
||||
|
||||
async generateCode(prompt: string, workspaceId: number) {
|
||||
// 获取工作区的AI配置
|
||||
const aiConfig = await this.aiConfigService.getAiConfigByWorkspace(workspaceId);
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { AiServiceAdapter } from './ai.adapter';
|
||||
|
||||
export class DeepSeekAdapter implements AiServiceAdapter {
|
||||
constructor(private readonly config: any) {}
|
||||
|
||||
// 实现AiServiceAdapter接口定义的方法
|
||||
async generateText(model: string, prompt: string, config?: Record<string, any>): Promise<string> {
|
||||
// 这里添加调用DeepSeek API的具体实现
|
||||
return `Response from DeepSeek: ${prompt}`;
|
||||
}
|
||||
|
||||
async chat(model: string, messages: Array<{role: string, content: string}>, config?: Record<string, any>): Promise<string> {
|
||||
// 这里添加调用DeepSeek API的具体实现
|
||||
return `Chat response from DeepSeek: ${messages[messages.length - 1].content}`;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import { AiServiceAdapter } from './ai.adapter';
|
||||
|
||||
export class TongyiAdapter implements AiServiceAdapter {
|
||||
constructor(private readonly config: any) {}
|
||||
|
||||
// 实现AiServiceAdapter接口定义的方法
|
||||
async generateText(model: string, prompt: string, config?: Record<string, any>): Promise<string> {
|
||||
// 这里添加调用Tongyi API的具体实现
|
||||
return `Response from Tongyi: ${prompt}`;
|
||||
}
|
||||
|
||||
async chat(model: string, messages: Array<{role: string, content: string}>, config?: Record<string, any>): Promise<string> {
|
||||
// 这里添加调用Tongyi API的具体实现
|
||||
return `Chat response from Tongyi: ${messages[messages.length - 1].content}`;
|
||||
}
|
||||
}
|
|
@ -13,7 +13,9 @@
|
|||
"forceConsistentCasingInFileNames": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@src/*": ["./src/*"]
|
||||
"@src/*": ["./src/*"],
|
||||
"./deepseek.adapter": ["./src/ai/deepseek.adapter"],
|
||||
"./tongyi.adapter": ["./src/ai/tongyi.adapter"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# 项目状态报告
|
||||
|
||||
## 日期
|
||||
2023-10-05
|
||||
2025-06-09
|
||||
|
||||
## 已完成功能
|
||||
1. 基础架构搭建
|
||||
|
|
Loading…
Reference in New Issue