feat: 添加投标信息按日期范围更新功能及AI推荐持久化
添加按日期范围更新投标信息的功能,支持日期范围选择和数据更新 实现AI推荐结果的持久化存储和加载功能 优化日期范围选择器的本地存储功能
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Controller, Post, Body } from '@nestjs/common';
|
||||
import { AiService } from './ai.service';
|
||||
import { Controller, Post, Body, Get } from '@nestjs/common';
|
||||
import { AiService, AIRecommendation } from './ai.service';
|
||||
|
||||
export class BidDataDto {
|
||||
title: string;
|
||||
@@ -9,6 +9,10 @@ export class BidsRequestDto {
|
||||
bids: BidDataDto[];
|
||||
}
|
||||
|
||||
export class SaveRecommendationsDto {
|
||||
recommendations: AIRecommendation[];
|
||||
}
|
||||
|
||||
@Controller('api/ai')
|
||||
export class AiController {
|
||||
constructor(private readonly aiService: AiService) {}
|
||||
@@ -17,4 +21,15 @@ export class AiController {
|
||||
async getRecommendations(@Body() request: BidsRequestDto) {
|
||||
return this.aiService.getRecommendations(request.bids);
|
||||
}
|
||||
|
||||
@Post('save-recommendations')
|
||||
async saveRecommendations(@Body() request: SaveRecommendationsDto) {
|
||||
await this.aiService.saveRecommendations(request.recommendations);
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
@Get('latest-recommendations')
|
||||
async getLatestRecommendations() {
|
||||
return this.aiService.getLatestRecommendations();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { AiController } from './ai.controller';
|
||||
import { AiService } from './ai.service';
|
||||
import { AiRecommendation } from './entities/ai-recommendation.entity';
|
||||
import { BidItem } from '../bids/entities/bid-item.entity';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule],
|
||||
imports: [
|
||||
ConfigModule,
|
||||
TypeOrmModule.forFeature([AiRecommendation, BidItem]),
|
||||
],
|
||||
controllers: [AiController],
|
||||
providers: [AiService],
|
||||
exports: [AiService],
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import OpenAI from 'openai';
|
||||
import { PromptString } from './Prompt';
|
||||
import { AiRecommendation as AiRecommendationEntity } from './entities/ai-recommendation.entity';
|
||||
import { BidItem } from '../bids/entities/bid-item.entity';
|
||||
|
||||
export interface BidDataDto {
|
||||
title: string;
|
||||
@@ -19,7 +23,13 @@ export class AiService {
|
||||
private readonly logger = new Logger(AiService.name);
|
||||
private openai: OpenAI;
|
||||
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
constructor(
|
||||
private readonly configService: ConfigService,
|
||||
@InjectRepository(AiRecommendationEntity)
|
||||
private readonly aiRecommendationRepository: Repository<AiRecommendationEntity>,
|
||||
@InjectRepository(BidItem)
|
||||
private readonly bidItemRepository: Repository<BidItem>,
|
||||
) {
|
||||
const apiKey = this.configService.get<string>('ARK_API_KEY');
|
||||
this.openai = new OpenAI({
|
||||
apiKey: apiKey || '',
|
||||
@@ -80,4 +90,57 @@ ${JSON.stringify(bids.map(b => b.title), null, 2)}`;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async saveRecommendations(recommendations: AIRecommendation[]): Promise<void> {
|
||||
this.logger.log('开始保存 AI 推荐结果');
|
||||
|
||||
try {
|
||||
// 删除所有旧的推荐
|
||||
await this.aiRecommendationRepository.clear();
|
||||
|
||||
// 保存新的推荐结果(只保存 title 和 confidence)
|
||||
const entities = recommendations.map(rec => {
|
||||
const entity = new AiRecommendationEntity();
|
||||
entity.title = rec.title;
|
||||
entity.confidence = rec.confidence;
|
||||
return entity;
|
||||
});
|
||||
|
||||
await this.aiRecommendationRepository.save(entities);
|
||||
this.logger.log(`成功保存 ${entities.length} 条 AI 推荐结果`);
|
||||
} catch (error) {
|
||||
this.logger.error('保存 AI 推荐失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getLatestRecommendations(): Promise<AIRecommendation[]> {
|
||||
this.logger.log('获取最新的 AI 推荐结果');
|
||||
|
||||
try {
|
||||
const entities = await this.aiRecommendationRepository.find({
|
||||
order: { confidence: 'DESC' }
|
||||
});
|
||||
|
||||
// 从 bid-items 表获取 url 和 source
|
||||
const result: AIRecommendation[] = [];
|
||||
for (const entity of entities) {
|
||||
const bidItem = await this.bidItemRepository.findOne({
|
||||
where: { title: entity.title }
|
||||
});
|
||||
|
||||
result.push({
|
||||
title: entity.title,
|
||||
url: bidItem?.url || '',
|
||||
source: bidItem?.source || '',
|
||||
confidence: entity.confidence
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
this.logger.error('获取最新 AI 推荐失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
src/ai/entities/ai-recommendation.entity.ts
Normal file
16
src/ai/entities/ai-recommendation.entity.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from 'typeorm';
|
||||
|
||||
@Entity('ai_recommendations')
|
||||
export class AiRecommendation {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
title: string;
|
||||
|
||||
@Column({ type: 'int' })
|
||||
confidence: number;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { BidItem } from '../bids/entities/bid-item.entity';
|
||||
import { Keyword } from '../keywords/keyword.entity';
|
||||
import { AiRecommendation } from '../ai/entities/ai-recommendation.entity';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -16,7 +17,7 @@ import { Keyword } from '../keywords/keyword.entity';
|
||||
username: configService.get<string>('DATABASE_USERNAME', 'root'),
|
||||
password: configService.get<string>('DATABASE_PASSWORD', 'root'),
|
||||
database: configService.get<string>('DATABASE_NAME', 'bidding'),
|
||||
entities: [BidItem, Keyword],
|
||||
entities: [BidItem, Keyword, AiRecommendation],
|
||||
synchronize: configService.get<boolean>('DATABASE_SYNCHRONIZE', true),
|
||||
}),
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user