과거공부모음

Nest.js에서 Google Vision API 사용하기

MUJA 2023. 4. 1. 23:50

프로젝트를 진행하면서 유사한 이미지를 추천해 주는 기능을 위해서 Vision을 이용해 사진에 라벨링 하는 기능을 구현했는데 복습하며 정리해 보도록 하겠다

 

Google Cloud Console을 먼저 세팅하자

https://cloud.google.com/vision/docs/setup?hl=ko 

 

빠른 시작: Vision API 설정  |  Google Cloud

의견 보내기 빠른 시작: Vision API 설정 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 가이드에서는 Vision을 처음 사용하는 데 필요한 모든 설정 단계를 제

cloud.google.com

 

해당 문서를 따라서 설정을 하면 json으로 된 키파일을 다운받을 수 있다 안전하게 보관해 두자

 

필요한 패키지를 먼저 다운로드하고 시작하자

npm install @google-cloud/vision --save

 

google vision api를 사용하기 위해서 class를 만들자

import vision, { ImageAnnotatorClient } from '@google-cloud/vision';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as _ from 'lodash';

@Injectable()
export class GoogleVisionService {
  client: ImageAnnotatorClient;

  constructor(private configSerivce: ConfigService) {
    const googlePrivateKey = this.configSerivce.get('GOOGLE_VISION_API_SECRET_KEY');
    const clientEmail = this.configSerivce.get('GOOGLE_VISION_API_CLIENT_EMAIL');
    this.client = new vision.ImageAnnotatorClient({
      credentials: {
        private_key: googlePrivateKey,
        client_email: clientEmail,
      },
    });
  }

  async imageLabeling(image: string) {
    return this.client
      .labelDetection(image)
      .then((results) => {
        const labels = results[0].labelAnnotations;
        if (_.isNil(labels)) return [];

        const result = labels.map((label) => {
          if (_.isString(label.description)) {
            return label.description;
          }
        });

        return [...new Set(result)];
      })
      .catch((err) => {
        console.log('error: ', err);
        return [];
      });
  }
}

아까 받은 json파일에서 API 시크릿키와 API 이메일을 가지고 vision 클라이언트를 생성하고 사용한다

imageLabeling에서 매개변수로 받은 이미지를 labelDetection메세드를 사용해서 해당 이미지에 대한 라벨링을 진행한다

중복되는 라벨이 존재하기 때문에 Set을 이용해서 중복값을 제거한 후 반환한다

 

만든 GoogleVisionService클래스를 사용하러 가보자

photospot.module에 의존성 주입을 시킨다

providers: [PhotospotService, S3Service, GoogleVisionService],

 

그리고 photospot.service로 가보자

async createImageKeyword(image: string, photoId: number): Promise<void> {
    const photoKeywords = await this.googleVisionService.imageLabeling(image);
    const keyword = [];
    for (const photoKeyword of photoKeywords) {
      if (_.isUndefined(photoKeyword)) {
        continue;
      }

      const preKeyword = await this.photoKeywordRepository.findOne({ where: { keyword: photoKeyword } });
      if (_.isNil(preKeyword)) {
        const insertKeyword = await this.photoKeywordRepository.save({ keyword: photoKeyword });
        keyword.push(insertKeyword);
      } else {
        keyword.push(preKeyword);
      }
    }
    const photo = await this.photoRepository.findOne({ where: { id: photoId } });
    if (_.isNil(photo)) {
      return;
    }
    photo.photoKeywords = keyword;
    await this.photoRepository.save(photo);
  }

포토스팟을 등록하는 부분에서 포토스팟에 포토를 등록하고 후 createImageKeyword를 호출한다

그렇다면 전달받은 이미지와 포토아이디를 가지고 라벨링 후 DB에 저장한다

이미 존재하는 키워드에 경우에는 중복되어 저장되는 걸 막기 위해서 preKeyword로 따로 지정하고

새로운 키워드의 경우 새로 만들어 저장 후 insertKeyword로 지정한다 그리고 각각 keyword 배열에 집어넣는다

포토아이디를 가지고 라벨링이 돼야 하는 해당 포토를 가져와 photoKeywords 컬럼을 keyword로 재할당 후 save를 시키는 방식으로 사진에 라벨링을 한다