Skip to content

Commit

Permalink
merge #320: 이미지 유해성 검사 API 사용
Browse files Browse the repository at this point in the history
[feat] 이미지 유해성 검사 API 사용
  • Loading branch information
yaongmeow authored Dec 10, 2023
2 parents 425eadf + 51aa07e commit 5d44183
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 9 deletions.
8 changes: 8 additions & 0 deletions BE/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions BE/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"rxjs": "^7.8.1",
"typeorm": "^0.3.17",
"typeorm-transactional": "^0.5.0",
"uuid": "^9.0.1",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^4.7.1"
},
Expand All @@ -55,6 +56,7 @@
"@types/multer": "^1.4.10",
"@types/node": "^20.3.1",
"@types/supertest": "^2.0.12",
"@types/uuid": "^9.0.7",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.42.0",
Expand Down
4 changes: 3 additions & 1 deletion BE/src/storage/storage.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Module } from '@nestjs/common';
import { StorageService } from './storage.service';
import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';

@Module({
imports: [HttpModule],
providers: [StorageService],
exports: [StorageService],
})
Expand Down
52 changes: 51 additions & 1 deletion BE/src/storage/storage.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { BadRequestException, Injectable } from '@nestjs/common';
import { firstValueFrom } from 'rxjs';
import { v4 as uuidv4 } from 'uuid';
import * as AWS from 'aws-sdk';

@Injectable()
export class StorageService {
constructor(private readonly httpService: HttpService) {}

private readonly s3: AWS.S3 = new AWS.S3({
endpoint: 'https://kr.object.ncloudstorage.com',
region: process.env.AWS_REGION,
Expand All @@ -21,6 +25,12 @@ export class StorageService {
}

async upload(path: string, file: Express.Multer.File) {
const analyzeImage = await this.analyzeImage(
file.originalname,
file.buffer.toString('base64')
);
this.validateAnalyzedImage(analyzeImage);

const uploadParams: AWS.S3.PutObjectRequest = {
Bucket: this.bucketName,
Key: path + this.generateFilename(file.originalname),
Expand Down Expand Up @@ -54,4 +64,44 @@ export class StorageService {

return await this.s3.deleteObject(deleteParams).promise();
}

private async analyzeImage(filename: string, fileData: string) {
const url = `https://clovagreeneye.apigw.ntruss.com/custom/v1/${process.env.GREENEYE_DOMAIN_ID}/${process.env.GREENEYE_SIGNATURE}/predict`;
const {
data: { images },
} = await firstValueFrom(
this.httpService.post(
url,
{
version: 'V1',
requestId: uuidv4(),
timestamp: Date.now(),
images: [{ name: filename, data: fileData }],
},
{
headers: {
'X-GREEN-EYE-SECRET': process.env.GREENEYE_SECRET_KEY,
'Content-Type': 'application/json',
},
}
)
);

return images[0].result;
}

private validateAnalyzedImage(result: {
adult: { confidence: number };
normal: { confidence: number };
sexy: { confidence: number };
porn: { confidence: number };
}) {
const normal = result.normal.confidence;
const sumOfOthers =
result.adult.confidence + result.porn.confidence + result.sexy.confidence;

if (normal < sumOfOthers) {
throw new BadRequestException('유해한 이미지가 포함되어 있습니다.');
}
}
}
2 changes: 2 additions & 0 deletions BE/src/timelines/timelines.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export const DATA_SOURCE = 'DATA_SOURCE';
export const TIMELINES_REPOSITORY = 'TIMELINES_REPOSITORY';
export const KAKAO_KEYWORD_SEARCH =
'https://dapi.kakao.com/v2/local/search/keyword';
export const PAPAGO_URL =
'https://naveropenapi.apigw.ntruss.com/nmt/v1/translation';
19 changes: 19 additions & 0 deletions BE/src/timelines/timelines.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { FileInterceptor } from '@nestjs/platform-express';
import { CreateTimelineDto } from './dto/create-timeline.dto';
import { UpdateTimelineDto } from './dto/update-timeline.dto';
import {
ApiBadRequestResponse,
ApiBearerAuth,
ApiConsumes,
ApiCreatedResponse,
Expand Down Expand Up @@ -88,6 +89,15 @@ export class TimelinesController {
},
},
})
@ApiBadRequestResponse({
schema: {
example: {
message: '유해한 이미지가 포함되어 있습니다.',
error: 'Bad Request',
statusCode: 400,
},
},
})
async create(
@Req() request,
@UploadedFile() image: Express.Multer.File,
Expand Down Expand Up @@ -168,6 +178,15 @@ export class TimelinesController {
})
@ApiConsumes('multipart/form-data')
@ApiOkResponse({ schema: { example: update_OK } })
@ApiBadRequestResponse({
schema: {
example: {
message: '유해한 이미지가 포함되어 있습니다.',
error: 'Bad Request',
statusCode: 400,
},
},
})
async update(
@Req() request,
@Param('id', ParseUUIDPipe) id: string,
Expand Down
5 changes: 2 additions & 3 deletions BE/src/timelines/timelines.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { TimelinesRepository } from './timelines.repository';
import { Timeline } from './entities/timeline.entity';
import { StorageService } from '../storage/storage.service';
import { PostingsService } from '../postings/postings.service';
import { KAKAO_KEYWORD_SEARCH } from './timelines.constants';
import { KAKAO_KEYWORD_SEARCH, PAPAGO_URL } from './timelines.constants';
import { PostingsRepository } from '../postings/repositories/postings.repository';

@Injectable()
Expand Down Expand Up @@ -166,7 +166,6 @@ export class TimelinesService {

async translate(id: string) {
const { description } = await this.findOne(id);
const url = 'https://naveropenapi.apigw.ntruss.com/nmt/v1/translation';
const body = {
source: 'ko',
target: 'en',
Expand All @@ -177,7 +176,7 @@ export class TimelinesService {
message: { result },
},
} = await firstValueFrom(
this.httpService.post(url, body, {
this.httpService.post(PAPAGO_URL, body, {
headers: {
'Content-Type': 'application/json',
'X-NCP-APIGW-API-KEY-ID': process.env.X_NCP_APIGW_API_KEY_ID,
Expand Down
8 changes: 4 additions & 4 deletions BE/src/users/users.module.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { StorageService } from 'src/storage/storage.service';
import { usersProvider } from './users.providers';
import { UserRepository } from './users.repository';
import { DatabaseModule } from 'src/database/database.module';
import { StorageModule } from '../storage/storage.module';
import { DatabaseModule } from '../database/database.module';

@Module({
imports: [DatabaseModule],
imports: [DatabaseModule, StorageModule],
controllers: [UsersController],
providers: [UsersService, StorageService, ...usersProvider, UserRepository],
providers: [UsersService, ...usersProvider, UserRepository],
exports: [UserRepository, UsersService],
})
export class UsersModule {}

0 comments on commit 5d44183

Please sign in to comment.