Skip to content

Commit

Permalink
feature:FUR-55 [BE]Config GenAI API key in setting DB
Browse files Browse the repository at this point in the history
  • Loading branch information
MinhhTien committed Jun 16, 2024
1 parent e8873b9 commit 8866041
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 25 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/develop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,8 @@ jobs:
echo DISCORD_WEBHOOK_TOKEN=${{ secrets.DISCORD_WEBHOOK_TOKEN }} >> .env
echo TRIPO_3D_AI_ENDPOINT=${{ vars.TRIPO_3D_AI_ENDPOINT }} >> .env
echo TRIPO_3D_AI_API_KEY=${{ secrets.TRIPO_3D_AI_API_KEY }} >> .env
echo EDEN_AI_ENDPOINT=${{ vars.EDEN_AI_ENDPOINT }} >> .env
echo EDEN_AI_API_KEY=${{ secrets.EDEN_AI_API_KEY }} >> .env
- name: Deploy
run: pm2 restart furnique-api
Expand Down
2 changes: 0 additions & 2 deletions example.env
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,9 @@ DISCORD_WEBHOOK_TOKEN=

#Tripo 3D AI API
TRIPO_3D_AI_ENDPOINT=https://api.tripo3d.ai
TRIPO_3D_AI_API_KEY=

#Eden AI
EDEN_AI_ENDPOINT=https://api.edenai.run
EDEN_AI_API_KEY=


## PAYMENT
Expand Down
2 changes: 1 addition & 1 deletion src/ai-generation/controllers/text-to-image.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class AIGenerationTextToImageController {
@ApiOkResponse({ type: TextToImageResponseDto })
@Post()
generate(@Req() req, @Body() generateTextToImageDto: GenerateTextToImageDto) {
generateTextToImageDto.providers = ['openai/dall-e-2', 'openai/dall-e-3', 'openai', "amazon", 'amazon/titan-image-generator-v1_premium', 'amazon/titan-image-generator-v1_standard']
generateTextToImageDto.providers = ['openai/dall-e-2']
generateTextToImageDto.resolution = "512x512"
generateTextToImageDto.customerId = _.get(req, 'user._id')
return this.aiGenerationTextToImageService.generateTextToImage(generateTextToImageDto)
Expand Down
17 changes: 12 additions & 5 deletions src/ai-generation/services/text-to-image.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { AIGenerationPlatform, AIGenerationPricing, AIGenerationType } from '@ai
import { GenerateTextToImageDto } from '@ai-generation/dtos/text-to-image.dto'
import { CustomerRepository } from '@customer/repositories/customer.repository'
import { Status } from '@common/contracts/constant'
import { SettingService } from '@setting/services/setting.service'
import { SettingKey } from '@setting/contracts/constant'

@Injectable()
export class AIGenerationTextToImageService {
Expand All @@ -20,19 +22,19 @@ export class AIGenerationTextToImageService {
private readonly aiGenerationRepository: AIGenerationRepository,
private readonly httpService: HttpService,
private readonly configService: ConfigService,
private readonly customerRepository: CustomerRepository
private readonly customerRepository: CustomerRepository,
private readonly settingService: SettingService
) {
this.config = this.configService.get('edenAI')
this.headersRequest = {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.config.apiKey}`
'Content-Type': 'application/json'
}
}

async generateTextToImage(generateTextToImageDto: GenerateTextToImageDto) {
const { customerId } = generateTextToImageDto

// Check limit AI generation
// 1. Check limit AI generation
const { credits } = await this.customerRepository.findOne({
conditions: {
_id: customerId,
Expand All @@ -43,10 +45,14 @@ export class AIGenerationTextToImageService {
throw new AppException(Errors.NOT_ENOUGH_CREDITS_ERROR)
}

// 2. Get API_KEY from DB
const settingValue = await this.settingService.getValue(SettingKey.EDEN_AI)

// 3. Run GenAI
const { data } = await firstValueFrom(
this.httpService
.post(`${this.config.endpoint}/v2/image/generation`, generateTextToImageDto, {
headers: this.headersRequest
headers: { ...this.headersRequest, Authorization: `Bearer ${settingValue['apiKey']}` }
})
.pipe(
catchError((error: AxiosError) => {
Expand All @@ -58,6 +64,7 @@ export class AIGenerationTextToImageService {
const result: any = Object.values(data)[0]
if (result?.status !== 'success') throw new AppException({ ...Errors.EDEN_AI_ERROR, data })

// 4. Save GenAI data, update credits
const imageUrl = result?.items[0]?.image_resource_url
await Promise.all([
this.aiGenerationRepository.create({
Expand Down
33 changes: 23 additions & 10 deletions src/ai-generation/services/text-to-model.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { Errors } from '@common/contracts/error'
import { AIGenerationPlatform, AIGenerationPricing, AIGenerationType } from '@ai-generation/contracts/constant'
import { CustomerRepository } from '@customer/repositories/customer.repository'
import { Status } from '@common/contracts/constant'
import { SettingService } from '@setting/services/setting.service'
import { SettingKey } from '@setting/contracts/constant'

@Injectable()
export class AIGenerationTextToModelService {
Expand All @@ -20,19 +22,19 @@ export class AIGenerationTextToModelService {
private readonly aiGenerationRepository: AIGenerationRepository,
private readonly httpService: HttpService,
private readonly configService: ConfigService,
private readonly customerRepository: CustomerRepository
private readonly customerRepository: CustomerRepository,
private readonly settingService: SettingService
) {
this.config = this.configService.get('tripo3dAI')
this.headersRequest = {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.config.apiKey}`
'Content-Type': 'application/json'
}
}

async generateTextToDraftModel(generateTextToDraftModelDto: GenerateTextToDraftModelDto) {
const { customerId } = generateTextToDraftModelDto

// Check limit AI generation
// 1. Check limit AI generation
const { credits } = await this.customerRepository.findOne({
conditions: {
_id: customerId,
Expand All @@ -43,10 +45,14 @@ export class AIGenerationTextToModelService {
throw new AppException(Errors.NOT_ENOUGH_CREDITS_ERROR)
}

// 2. Get API_KEY from DB
const settingValue = await this.settingService.getValue(SettingKey.TRIPO_3D_AI)

// 3. Run GenAI
const { data } = await firstValueFrom(
this.httpService
.post(`${this.config.endpoint}/v2/openapi/task`, generateTextToDraftModelDto, {
headers: this.headersRequest
headers: { ...this.headersRequest, Authorization: `Bearer ${settingValue['apiKey']}` }
})
.pipe(
catchError((error: AxiosError) => {
Expand All @@ -57,6 +63,7 @@ export class AIGenerationTextToModelService {
)
if (data.code !== 0) throw new AppException({ ...Errors.TRIPO_3D_AI_ERROR, data })

// 4. Save GenAI data, update credits
await Promise.all([
this.aiGenerationRepository.create({
customerId,
Expand All @@ -77,13 +84,19 @@ export class AIGenerationTextToModelService {
}

async getTask(taskId: string) {
const settingValue = await this.settingService.getValue(SettingKey.TRIPO_3D_AI)

const { data } = await firstValueFrom(
this.httpService.get(`${this.config.endpoint}/v2/openapi/task/${taskId}`, { headers: this.headersRequest }).pipe(
catchError((error: AxiosError) => {
this.logger.error(error?.response?.data)
throw new AppException({ ...Errors.TRIPO_3D_AI_ERROR, data: error?.response?.data })
this.httpService
.get(`${this.config.endpoint}/v2/openapi/task/${taskId}`, {
headers: { ...this.headersRequest, Authorization: `Bearer ${settingValue['apiKey']}` }
})
)
.pipe(
catchError((error: AxiosError) => {
this.logger.error(error?.response?.data)
throw new AppException({ ...Errors.TRIPO_3D_AI_ERROR, data: error?.response?.data })
})
)
)
if (data.code !== 0) throw new AppException({ ...Errors.TRIPO_3D_AI_ERROR, data })
return data?.data
Expand Down
4 changes: 3 additions & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { AnalyticModule } from '@analytic/analytic.module'
import { PaymentModule } from '@payment/payment.module'
import { AIGenerationModule } from '@ai-generation/ai-generation.module'
import { ReviewModule } from '@review/review.module'
import { SettingModule } from '@setting/setting.module'

@Module({
imports: [
Expand Down Expand Up @@ -133,7 +134,8 @@ import { ReviewModule } from '@review/review.module'
AnalyticModule,
PaymentModule,
AIGenerationModule,
ReviewModule
ReviewModule,
SettingModule
],
controllers: [AppController],
providers: [AppService]
Expand Down
6 changes: 2 additions & 4 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,10 @@ export default () => ({
webhookToken: process.env.DISCORD_WEBHOOK_TOKEN,
},
tripo3dAI: {
endpoint: process.env.TRIPO_3D_AI_ENDPOINT,
apiKey: process.env.TRIPO_3D_AI_API_KEY
endpoint: process.env.TRIPO_3D_AI_ENDPOINT
},
edenAI: {
endpoint: process.env.EDEN_AI_ENDPOINT,
apiKey: process.env.EDEN_AI_API_KEY
endpoint: process.env.EDEN_AI_ENDPOINT
},
NODE_ENV: process.env.NODE_ENV,
JWT_ACCESS_SECRET: process.env.JWT_ACCESS_SECRET || 'accessSecret',
Expand Down
4 changes: 4 additions & 0 deletions src/setting/contracts/constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum SettingKey {
EDEN_AI = 'EDEN_AI',
TRIPO_3D_AI= 'TRIPO_3D_AI'
}
12 changes: 12 additions & 0 deletions src/setting/repositories/setting.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { PaginateModel } from 'mongoose'
import { Injectable } from '@nestjs/common'
import { InjectModel } from '@nestjs/mongoose'
import { AbstractRepository } from '@common/repositories'
import { Setting, SettingDocument } from '@setting/schemas/setting.schema'

@Injectable()
export class SettingRepository extends AbstractRepository<SettingDocument> {
constructor(@InjectModel(Setting.name) model: PaginateModel<SettingDocument>) {
super(model)
}
}
34 changes: 34 additions & 0 deletions src/setting/schemas/setting.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
import { HydratedDocument } from 'mongoose'
import { Transform } from 'class-transformer'
import { SettingKey } from '@setting/contracts/constant';

export type SettingDocument = HydratedDocument<Setting>;

@Schema({
collection: 'settings',
timestamps: true,
toJSON: {
transform(doc, ret) {
delete ret.__v
}
}
})
export class Setting {
constructor(id?: string) {
this._id = id;
}
@Transform(({ value }) => value?.toString())
_id?: string;

@Prop({ enum: SettingKey, required: true })
key: SettingKey;

@Prop({ type: Object, required: true })
value: object;

@Prop({ type: Boolean, default: true })
enabled: boolean;
}

export const SettingSchema = SchemaFactory.createForClass(Setting);
29 changes: 29 additions & 0 deletions src/setting/services/setting.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Injectable } from '@nestjs/common';
import { SettingRepository } from '@setting/repositories/setting.repository';
import { SettingKey } from '@setting/contracts/constant';

@Injectable()
export class SettingService {
constructor(readonly settingRepository: SettingRepository) {}

async getValue(key: SettingKey) {
return (
await this.settingRepository.findOne({
conditions: {
key: key.toString(),
enabled: true,
},
})
)?.value;
}

async updateValue(key: SettingKey, value: any) {
return await this.settingRepository.findOneAndUpdate(
{
key: key.toString(),
enabled: true,
},
{ value },
);
}
}
15 changes: 15 additions & 0 deletions src/setting/setting.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Global, Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { Setting, SettingSchema } from '@setting/schemas/setting.schema';
import { SettingService } from '@setting/services/setting.service';
import { SettingRepository } from '@setting/repositories/setting.repository';

@Global()
@Module({
imports: [
MongooseModule.forFeature([{ name: Setting.name, schema: SettingSchema }]),
],
providers: [SettingService, SettingRepository],
exports: [SettingService],
})
export class SettingModule {}
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@payment/*": ["src/payment/*"],
"@ai-generation/*": ["src/ai-generation/*"],
"@review/*": ["src/review/*"],
"@setting/*": ["src/setting/*"],
"@src/*": ["src/*"]
},

Expand Down

0 comments on commit 8866041

Please sign in to comment.