본문 바로가기

프로젝트/나만의명언집

사용자가 비속어를 사용한다면, 그것을 어떻게 필터링할까요?(with NodeJS & GPT)

반응형

오늘의 명언

 

 

비속어 필터링이 없는 사이트

제가 개인 프로젝트인 명언 웹 사이트를 만들고 배포까지 했지만, 그리고 트래픽도 없지만, 이 부분은 꼭 필요하다고 방금 떠오른 부분이 있습니다.

 

그건 바로 비속어 필터링인데요. 사실 사이트 배포 후 운영을 생각하기 전에는 이 사실을 깊이 있게 고려하지 않았을 것 같은데, 실제 배포하고 운영한다고 가정하니까 여러 문제들이 사이트 내에 잔재하고 있다는 사실을 깨달아가고 있습니다.

 

그래서 이 문제를 해결하기 위해 추가적인 기능이 필요한 상황이라 이 부분을 추가하는 시간을 가져볼까 합니다.

 

필터링 하는 방법은 뭐가 있을까요?

나름 생각해본 방법들에는 정규표현식을 이용한 방법, 일반적인 배열에 키워드를 담아서 일치하는 여부에 따라 처리하는 방법이 있었고,

 

좀 비용이 들더라도 보다 안정적인 필터링을 하고자 한다면 유료 API 를 사용할 수 있겠다는 생각이 들었습니다. 이런 점에서는 GPT 와 같은 인공지능을 사용하여 필터링하는 방법도 있었습니다. 

 

그러면 어떤 방법을 선택하는게 비용을 최소화하면서 효과적인 처리가 될까요? 저 같은 경우에는 해당 도구로 OpenAI 의 API 를 사용하기로 하였습니다. 비용을 아에 제로에 가깝게 한다면 직접 비속어를 필터링하는 기능을 구현해도 좋겠지만, 한국어의 경우는 "씌벍놈 " 와 같이 꼬아서 해버리면 필터링하기 정말 힘들 것 같다는 생각이 들었습니다.

 

그런데 GPT 의 경우에는 이를 맡겨 두니 아래와 같이 응답을 하더군요.

 

다만 아래와 같이 복잡하게 꼬아두면 인식을 못하는 부분도 있긴 합니다.

 

그럼에도 테스트를 해본 결과 특정 언어에 제한적이지 않고, 범용적으로 넓은 범위에 거쳐 비속어를 필터링할 수 있는 친구라 생각되어 선택하였습니다.

 

GPT 말고도 비슷한 친구가 있긴하네요.

GPT 뿐만 아니라 찾아보면 다양한 목적으로 사용 가능한 API가 있었고, 그 중에서 Moderation 이라는 모델이 있습니다. 기본적인 텍스트 생성용 GPT 와는 목적이 다르기 더 추가적인 데이터 훈련이 이루어졌을 것이니 도구를 선택한다면 이 친구를 선택하는게 명확하겠죠. 하지만 제가 테스트로 사용해본 결과 대부분의 욕설과 비속어를 걸러주지 못하는 문제가 보였습니다. 

 

분명 GPT 의 경우에는 욕설로 분류되었던 것이 예제를 기반으로 구현했던 Moderation 에서는 반대로 해석하더라구요. 

 

제가 잘못 사용한 것인지, 아니면 아직 부족한 부분이 있는 것인지 모르므로 테스트 결과 더 정확하고 유연한 응답을 이끌어 낼 수 있는 GPT 모델을 사용하기로 하였습니다.

 

구현은 어떻게?

뭐 사실 구현이라는 것은 만들어진 템플릿을 잘 가져와서 현재 프로젝트에 맡게 꾸며주기만 하면 될 일이니 어려운 일은 아닙니다. 

 

저의 프로젝트는 NextJS 이므로 NodeJS 에서 사용하는 예제를 바탕으로 다음과 같이 프롬프트를 설정하였습니다.

 

사용자가 비속어 등을 사용하면 true를 반환하고, 그렇지 않으면 false를 반환하게 하였는데요. 무엇보다 왜 그렇게 판단했는지 이유가 중요하므로 reason 에 그 이유를 담아서 JSON 형태로 반환해달라고 지시하였습니다.

참고로 JSON 으로 반환하려면 response_format 을 type : json_object 로 명시해두어야 합니다. 안 그러면 에러가 발생하거든요. 그리고 system 역할을 부여할 gpt 에게도 명시적으로 응답을 JSON 객체 형태로 응답하라고 content 에 적어두어야 합니다. 이 두 가지는 매우 중요한 부분이니 참고하셔서 적용하시길 바랍니다. 이해가 안 되신다면 제가 적은 예시 프롬프트는 참고해보시면 됩니다. 나머지는 공식 문서를 보시면 자세한 설명이 나와 있으니 굳이 설명하지는 않겠습니다.

 

  const response = await openai.chat.completions.create({
    model: 'gpt-3.5-turbo-0125',
    response_format: { "type": 'json_object' },
    messages: [
      {
        role: 'system',
        content: "Your role is to return true if the user uses profanity, swearing, or inappropriate language; otherwise, return false. The response format should be in the form JSON Object of {judgment: false, reason: ''}. Please write the reason in Korean"
      },
      {
        role: 'user',
        content: content[0] + content[1] + content[2],
      },
    ],
    temperature: 0.5,
    max_tokens: 120,
    top_p: 1,
  })

 

 

실제 테스트 해보니?

첫 번째 테스트 케이스 

첫 번째 테스트 케이스는 무난한 비속어를 사용하여 테스트 해보았습니다. 결과적으로 제가 원하는 응답을 해주었네요

 

두 번째 테스트 케이스

두 번째 테스트 케이스는 조금 내용을 꼬아서 해보았습니다. 생각보다 꼬아둔 표현도 잘 필터링 해주네요!

 

 

 

 

마무리

이제 이 녀석을 저의 프로젝트에 무사히 적용만 하면 될 것 같습니다. 비싼 돈을 사용하지 않고도 조금의 토큰만 사용하면 필터링 할 수 있으니 비용적으로나 활용성에 있어서도 큰 이점이 남는게 아닌가 싶습니다. 

 

뭔가 글이 흐지부지하고 끝난 것 같지만, 사실상이게 끝입니다. 나머지는 해당 기능을 활용해서 필터링이 필요한 부분에 함수를 호출만 하면 되므로 그 뒤는 제가 알아서  할 일 이겠죠. 그럼이만 포스트를 읽어주셔서 감사합니다. 좋은 하루 되세요

 

 

 

반응형