-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature:FUR-13 [BE][Web] Integrate AI Generate text to 3D model produ…
…ct API (#102)
- Loading branch information
Showing
14 changed files
with
299 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { Global, Module } from '@nestjs/common' | ||
import { MongooseModule } from '@nestjs/mongoose' | ||
import { HttpModule } from '@nestjs/axios' | ||
import { AIGeneration, AIGenerationSchema } from './schemas/ai-generation.schema' | ||
import { CustomerModule } from '@customer/customer.module' | ||
import { AIGenerationTextToModelController } from './controllers/text-to-model.controller' | ||
import { AIGenerationTextToModelService } from './services/text-to-model.service' | ||
import { AIGenerationRepository } from './repositories/ai-generation.repository' | ||
|
||
@Global() | ||
@Module({ | ||
imports: [ | ||
MongooseModule.forFeature([{ name: AIGeneration.name, schema: AIGenerationSchema }]), | ||
HttpModule, | ||
CustomerModule | ||
], | ||
controllers: [AIGenerationTextToModelController], | ||
providers: [AIGenerationTextToModelService, AIGenerationRepository], | ||
exports: [AIGenerationTextToModelService, AIGenerationRepository] | ||
}) | ||
export class AIGenerationModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
export enum AIGenerationPlan { | ||
FREE = 'FREE', | ||
PREMIUM = 'PREMIUM' | ||
} | ||
|
||
export enum AIGenerationType { | ||
TEXT_TO_MODEL = 'TEXT_TO_MODEL' | ||
} | ||
|
||
export enum AIGenerationTaskStatus { | ||
QUEUED = 'queued', | ||
RUNNING = 'running', | ||
SUCCESS = 'success', | ||
FAILED = 'failed', | ||
CANCELLED = 'cancelled', | ||
UNKNOWN = 'unknown' | ||
} | ||
|
||
export enum AIGenerationTaskProgress { | ||
QUEUEING = 0, | ||
RUNNING = 'RUNNING', | ||
SUCCESS = 100 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { Body, Controller, Get, Param, Post, Req, UseGuards } from '@nestjs/common' | ||
import { ApiBearerAuth, ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger' | ||
import * as _ from 'lodash' | ||
import { Roles } from '@auth/decorators/roles.decorator' | ||
import { UserRole } from '@common/contracts/constant' | ||
import { RolesGuard } from '@auth/guards/roles.guard' | ||
import { JwtAuthGuard } from '@auth/guards/jwt-auth.guard' | ||
import { AIGenerationTextToModelService } from '@ai-generation/services/text-to-model.service' | ||
import { GenerateTextToDraftModelDto, TextToModelTaskResponseDto } from '@ai-generation/dtos/text-to-model.dto' | ||
|
||
@ApiTags('AIGeneration - TextToModel') | ||
@ApiBearerAuth() | ||
@Roles(UserRole.CUSTOMER) | ||
@UseGuards(JwtAuthGuard.ACCESS_TOKEN, RolesGuard) | ||
@Controller('text-to-model') | ||
export class AIGenerationTextToModelController { | ||
constructor(private readonly aiGenerationTextToModelService: AIGenerationTextToModelService) {} | ||
|
||
@ApiOperation({ | ||
summary: 'Generate draft model from text' | ||
}) | ||
@ApiOkResponse({ type: TextToModelTaskResponseDto }) | ||
@Post() | ||
generate(@Req() req, @Body() generateTextToDraftModelDto: GenerateTextToDraftModelDto) { | ||
generateTextToDraftModelDto.type = 'text_to_model' | ||
generateTextToDraftModelDto.customerId = _.get(req, 'user._id') | ||
return this.aiGenerationTextToModelService.generateTextToDraftModel(generateTextToDraftModelDto) | ||
} | ||
|
||
@ApiOperation({ | ||
summary: 'Get task of model' | ||
}) | ||
@Get(':taskId') | ||
@ApiOkResponse({ type: TextToModelTaskResponseDto }) | ||
getTask(@Param('taskId') taskId: string) { | ||
return this.aiGenerationTextToModelService.getTask(taskId) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { ApiProperty } from '@nestjs/swagger' | ||
import { DataResponse } from '@common/contracts/openapi-builder' | ||
import { IsNotEmpty, MaxLength } from 'class-validator' | ||
import { AIGenerationTaskProgress, AIGenerationTaskStatus } from '@ai-generation/contracts/constant' | ||
|
||
export class GenerateTextToDraftModelDto { | ||
@ApiProperty() | ||
@IsNotEmpty() | ||
@MaxLength(1024) | ||
prompt: string | ||
|
||
// @ApiProperty() | ||
// @IsNotEmpty() | ||
// @MaxLength(255) | ||
// negative_prompt?: string | ||
|
||
type?: string | ||
customerId?: string | ||
} | ||
|
||
export class TextToDraftModelDto { | ||
@ApiProperty({ | ||
example: '1ec04ced-4b87-44f6-a296-beee80777941' | ||
}) | ||
task_id: string | ||
} | ||
|
||
export class TextToDraftModelResponseDto extends DataResponse(TextToDraftModelDto) {} | ||
|
||
|
||
export class TextToModelTaskDto { | ||
@ApiProperty() | ||
task_id: string | ||
|
||
@ApiProperty() | ||
type: string | ||
|
||
@ApiProperty({ enum: AIGenerationTaskStatus }) | ||
status: AIGenerationTaskStatus | ||
|
||
@ApiProperty() | ||
input: object | ||
|
||
@ApiProperty({ | ||
example: { | ||
model: 'model url', | ||
rendered_image: 'preview image' | ||
} | ||
}) | ||
output: { | ||
model: string | ||
rendered_image: string | ||
} | ||
|
||
@ApiProperty({ | ||
enum: AIGenerationTaskProgress | ||
}) | ||
progress: AIGenerationTaskProgress | ||
|
||
@ApiProperty() | ||
create_time: string | ||
} | ||
|
||
export class TextToModelTaskResponseDto extends DataResponse(TextToModelTaskDto) {} |
12 changes: 12 additions & 0 deletions
12
src/ai-generation/repositories/ai-generation.repository.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { AIGeneration, AIGenerationDocument } from '@ai-generation/schemas/ai-generation.schema' | ||
|
||
@Injectable() | ||
export class AIGenerationRepository extends AbstractRepository<AIGenerationDocument> { | ||
constructor(@InjectModel(AIGeneration.name) model: PaginateModel<AIGenerationDocument>) { | ||
super(model) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose' | ||
import { HydratedDocument } from 'mongoose' | ||
import * as paginate from 'mongoose-paginate-v2' | ||
import { Transform } from 'class-transformer' | ||
import { ApiProperty } from '@nestjs/swagger' | ||
import { AIGenerationType } from '../contracts/constant' | ||
|
||
export type AIGenerationDocument = HydratedDocument<AIGeneration> | ||
|
||
@Schema({ | ||
collection: 'ai-generations', | ||
timestamps: true, | ||
toJSON: { | ||
transform(doc, ret) { | ||
delete ret.__v | ||
} | ||
} | ||
}) | ||
export class AIGeneration { | ||
constructor(id?: string) { | ||
this._id = id | ||
} | ||
@ApiProperty() | ||
@Transform(({ value }) => value?.toString()) | ||
_id: string | ||
|
||
@ApiProperty() | ||
@Prop({ type: String }) | ||
customerId: string | ||
|
||
@ApiProperty({ enum: AIGenerationType }) | ||
@Prop({ enum: AIGenerationType, default: AIGenerationType.TEXT_TO_MODEL }) | ||
type: AIGenerationType | ||
|
||
@ApiProperty() | ||
@Prop({ type: String }) | ||
taskId: string // used for TEXT_TO_MODEL | ||
|
||
// more prop for other type | ||
} | ||
|
||
export const AIGenerationSchema = SchemaFactory.createForClass(AIGeneration) | ||
|
||
AIGenerationSchema.plugin(paginate) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { Injectable, Logger } from '@nestjs/common' | ||
import { AIGenerationRepository } from '@ai-generation/repositories/ai-generation.repository' | ||
import { HttpService } from '@nestjs/axios' | ||
import { ConfigService } from '@nestjs/config' | ||
import { catchError, firstValueFrom } from 'rxjs' | ||
import { AxiosError } from 'axios' | ||
import { GenerateTextToDraftModelDto } from '@ai-generation/dtos/text-to-model.dto' | ||
import { AppException } from '@common/exceptions/app.exception' | ||
import { Errors } from '@common/contracts/error' | ||
import { AIGenerationType } from '@ai-generation/contracts/constant' | ||
|
||
@Injectable() | ||
export class AIGenerationTextToModelService { | ||
private readonly logger = new Logger(AIGenerationTextToModelService.name) | ||
private config | ||
private headersRequest | ||
constructor( | ||
private readonly aiGenerationRepository: AIGenerationRepository, | ||
private readonly httpService: HttpService, | ||
private readonly configService: ConfigService, | ||
) { | ||
this.config = this.configService.get('tripo3dAI') | ||
this.headersRequest = { | ||
'Content-Type': 'application/json', | ||
Authorization: `Bearer ${this.config.apiKey}` | ||
} | ||
} | ||
|
||
async generateTextToDraftModel(generateTextToDraftModelDto: GenerateTextToDraftModelDto) { | ||
const {customerId} = generateTextToDraftModelDto | ||
|
||
// TODO: Check limit AI generation here | ||
|
||
const { data } = await firstValueFrom( | ||
this.httpService | ||
.post(`${this.config.endpoint}/v2/openapi/task`, generateTextToDraftModelDto, { | ||
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 }) | ||
}) | ||
) | ||
) | ||
if (data.code !== 0) throw new AppException({ ...Errors.TRIPO_3D_AI_ERROR, data }) | ||
|
||
await this.aiGenerationRepository.create({ | ||
customerId, | ||
type: AIGenerationType.TEXT_TO_MODEL, | ||
taskId: data?.data?.task_id | ||
}) | ||
|
||
return data?.data | ||
} | ||
|
||
async getTask(taskId: string) { | ||
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 }) | ||
}) | ||
) | ||
) | ||
if (data.code !== 0) throw new AppException({ ...Errors.TRIPO_3D_AI_ERROR, data }) | ||
return data?.data | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters