Skip to content

Conversation

@sese2204
Copy link
Contributor

@sese2204 sese2204 commented Dec 15, 2025

🌍 이슈 번호

#418

📝 구현 내용

  1. 새로 생성된 파일:
  • (infra/CheerTalkBotClient) - 봇 클라이언트 공통 인터페이스
  • (infra/HuggingfaceConfig) - WebClient Bean 설정
  • (infra/HuggingfaceClient) - Huggingface API 호출 구현
  • (domain/CheerTalkBotFilterHistoryRepository) - History 저장 Repository
  • (infra/ClarifaiConfig) - WebClient Bean 설정
  • (infra/ClarifaiClient) - Clarifai API 호출 구현
  1. 수정된 파일:
  • CheerTalkBotFilterHistory.java (domain/CheerTalkBotFilterHistory.java:43) - 생성자 추가
  • CheerTalkService.java (application/CheerTalkService.java:93) - filterByBot() 메서드 구현

🍀 확인해야 할 부분

  • (추후) 재시도 로직: Primary API 실패 시 Fallback API 호출
  • CheerTalkService의 filterByBot을 확인해주셨으면 하는데 우선 재시도 로직이 어떻게 들어갈 지 모르겠어서 hugging face api만 호출하고 있습니다. 이 부분 논의가 필요할 듯
  • 효빈이가 cheerTalk에 ai에 의해 차단됨 상태 하나 추가해서 구현해달라고 했는데 필요성을 모르겠어서 오늘 회의때 설명 부탁해요
  • 아래 제미나이 리뷰들도 같이 봐주시면 좋을 것 같아요

@sese2204 sese2204 linked an issue Dec 15, 2025 that may be closed by this pull request
@gemini-code-assist
Copy link

Summary of Changes

Hello @sese2204, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 응원톡(CheerTalk) 기능에 AI 기반 콘텐츠 필터링 시스템을 도입합니다. Huggingface와 Clarifai AI 모델을 활용하여 부적절한 콘텐츠를 감지하고, 필터링 이력을 저장하는 기능을 구현합니다. 이를 통해 응원톡의 건전한 환경을 조성하고, 향후 확장 가능한 AI 필터링 인프라를 마련합니다.

Highlights

  • AI API 연동: 응원톡 콘텐츠 필터링을 위해 Huggingface 및 Clarifai AI API 연동을 위한 클라이언트와 공통 인터페이스가 구현되었습니다.
  • 필터링 이력 저장: AI 봇 필터링 이력을 저장하는 CheerTalkBotFilterHistoryRepository가 추가되었으며, 이력 객체 생성을 위한 생성자가 CheerTalkBotFilterHistory에 추가되었습니다.
  • 응원톡 필터링 로직 구현: CheerTalkServicefilterByBot() 메서드가 구현되어 Huggingface API를 호출하고, 응답을 파싱하여 필터링 이력을 저장하는 AI 기반 콘텐츠 필터링을 수행합니다.
  • API 설정 추가: Huggingface 토큰과 Clarifai API 키 설정을 위한 환경 변수 및 관련 WebClient Bean 설정이 추가되었습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

이번 PR은 외부 AI API를 연동하여 응원톡의 비속어를 필터링하는 기능을 구현하셨네요. CheerTalkBotClient 인터페이스를 통해 여러 클라이언트를 지원할 수 있는 기반을 마련한 점이 좋습니다. 전반적으로 좋은 방향으로 개발되고 있지만, 코드의 유지보수성, 안정성, 그리고 성능을 더욱 향상시키기 위한 몇 가지 제안 사항을 드립니다. 주요 내용은 다음과 같습니다: 필터링 로직을 별도 서비스로 분리, 필터링 히스토리 데이터 보강, 하드코딩된 API 엔드포인트 외부 설정화, 그리고 비동기 API 호출 방식에 대한 고려입니다.

);

return clarifaiWebClient.post()
.uri("/users/beomi/apps/text-moderation/models/moderation-abuse-korean/versions/f6fb536be02f4c34a92be44c1093ce55/outputs")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

API의 엔드포인트 URI가 하드코딩되어 있습니다. 모델 버전이나 사용자 정보가 변경될 경우 코드를 직접 수정해야 하므로 유지보수가 어렵습니다. 이 URI는 application.yml과 같은 외부 설정 파일로 분리하여 관리하는 것이 좋습니다.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yml 에 넣는 게 좋을 것 같아요~

예를 들어 갑자기 외부에서 엔드포인트를 변경해버리면 저희도 빠르게 대응해서 재배포 해야 할 수 있도록 yml 과 같은 설정 파일에 넣는 게 좋을 것 같습니당

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요거는 yml에 안 넣고 이렇게 직접 넣나용?

@Override
public JsonNode detectAbusiveContent(String content) {
return huggingfaceWebClient.post()
.uri("/smilegate-ai/kor_unsmile")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

API의 엔드포인트 URI가 하드코딩되어 있습니다. 모델 이름이 변경될 경우 코드를 직접 수정해야 하므로 유지보수가 어렵습니다. 이 URI는 application.yml과 같은 외부 설정 파일로 분리하여 관리하는 것이 좋습니다.

Comment on lines +24 to +34
Map<String, Object> requestBody = Map.of(
"inputs", List.of(
Map.of(
"data", Map.of(
"text", Map.of(
"raw", content
)
)
)
)
);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

API 요청 본문을 Map.ofList.of를 중첩하여 생성하고 있습니다. 현재 구조는 간단하지만, 요청 본문이 더 복잡해지거나 필드가 추가될 경우 가독성이 떨어지고 오류가 발생하기 쉽습니다. 요청 본문을 위한 별도의 DTO(Data Transfer Object) 클래스(예: ClarifaiRequestDto)를 정의하여 사용하면 타입 안정성을 높이고 코드를 더 명확하게 만들 수 있습니다.

Copy link
Contributor

@Jin409 Jin409 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금 secret key 가 local yml 에만 있는 것 같은데, 다른 yml 에도 추가가 필요할 것 같아요. 추가적으로, uri 들을 yml 에 넣는 게 좋을 것 같습니다~!

제외하고는 의존성 방향 흐름이나 인터페이스 구조도 좋은 것 같아요

);

return clarifaiWebClient.post()
.uri("/users/beomi/apps/text-moderation/models/moderation-abuse-korean/versions/f6fb536be02f4c34a92be44c1093ce55/outputs")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yml 에 넣는 게 좋을 것 같아요~

예를 들어 갑자기 외부에서 엔드포인트를 변경해버리면 저희도 빠르게 대응해서 재배포 해야 할 수 있도록 yml 과 같은 설정 파일에 넣는 게 좋을 것 같습니당

@Bean
public WebClient clarifaiWebClient() {
return WebClient.builder()
.baseUrl("https://api.clarifai.com/v2")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요것도~!

Copy link
Contributor

@hyobin-yang hyobin-yang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

구조 좋으네요~~ 수고하셨습니당~!👍

BotType supports();

JsonNode detectAbusiveContent(String content);
} No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍👍

.retrieve()
.bodyToMono(JsonNode.class)
.block();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서 예외처리 안 해도 되나요? 밖에서 잡나?

- 서비스 책임 분리 , cheertalk id 넘기도록 메소드 수정
- 봇에 의해 차단됨 상태 추가를 위해 cheertalk의 상태를 enum으로 변경
- ai 모델의 이름으로 클래스 네이밍 통일
Copy link
Contributor

@hyobin-yang hyobin-yang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

역시 필드 하나 추가하니 파생되는 로직이 많으네요 테스트까지 고생하셨습니당👍

JsonNode rawResponse = korUnsmileClient.detectAbusiveContent(content);
int latencyMs = (int) (System.currentTimeMillis() - startTime);

BotType botType = korUnsmileClient.supports();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

흠 뭔가 다시 보니까 supports라는 메서드명이 좀 모호한 것 같기도 하네요

);

return clarifaiWebClient.post()
.uri("/users/beomi/apps/text-moderation/models/moderation-abuse-korean/versions/f6fb536be02f4c34a92be44c1093ce55/outputs")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요거는 yml에 안 넣고 이렇게 직접 넣나용?

CheerTalk cheerTalk = entityUtils.getEntity(cheerTalkId, CheerTalk.class);

JsonNode rawResponse = korUnsmileClient.detectAbusiveContent(content);
int latencyMs = (int) (System.currentTimeMillis() - startTime);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

int로 변환하는 이유는 어차피 int 최댓값을 넘어갈 일은 없기 때문인가요?

package com.sports.server.command.cheertalk.domain;

public enum CheerTalkBlockStatus {
ACTIVE,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACTIVE가 뭔가 활성상태.. 같은 느낌이라 개인적으로는 처음에 좀 헷갈렸어서 클래스명이 CheerTalkBlockStatus으로 블록 상태를 나타내는 거니까 NONE(차단 상태 X)는 어떠려나요? 이것도 약간 애매한 것 같기도 하고..??
흠 지금도 괜찮으려나

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] ai api 호출하는 부분 구현

4 participants