Skip to content

Comments

[Feat] Connect GPT API#9

Merged
yeonju73 merged 11 commits intomainfrom
feat/#8/connect-gpt-api
Jul 26, 2025
Merged

[Feat] Connect GPT API#9
yeonju73 merged 11 commits intomainfrom
feat/#8/connect-gpt-api

Conversation

@yeonju73
Copy link
Contributor

@yeonju73 yeonju73 commented Jul 26, 2025

💻 Related Issue


🚀 Work Description

  • GPT API 연결
스크린샷 2025-07-26 17 05 52 - 서버의 request body와 일치시켰습니다.
  • 더미 예시 데이터로 프롬프트 엔지니어링 진행
  • app.prompts.data.fraud_examples 에서 유형별 예시 데이터를 관리하며,
  • app.prompts.fraud_prompts 에서 프롬프트에 지시사항과 예시데이터를 주입하였습니다.

🙇🏻‍♀️ To Reviewer

  • 현재는 모두 더미 예시 데이터로 프롬프트 개발을 진행하였습니다.
  • 현재 gpt api 결제수단을 아직 등록하지 않았는데 api 호출이 잘 됩니다..! Usage의 Total Spend도 0달러로 찍히고 있습니다.
  • 모든 유형의 3-4개의 예시를 assistant 로 매번 프롬프트에 입력하는 것은 input token 매우 많이 소모될 것 같습니다.. 그래서 대안으로 미리 만들어놓은 프롬프트를 연결해서 쓰는 Reusable Prompt 방식도 알아보았는데, 프롬프트 생성을 하려면 결제 수단을 등록하라고 떠서 추후 도입해보면 좋을 것 같습니다! 지금 도입하지 않은 이유는 무료로도 잘 작동하기 때문입니다...
  • Reusable Prompt https://platform.openai.com/docs/guides/text#reusable-prompts
  • 프로젝트의 요구사항에 맞게 지시사항 수정도 추후 진행해야할 것 같습니다.

➕ Next

  • 예시 데이터 수집
  • 프롬프트 지시사항 수정
  • spring 서버와 연결

Summary by CodeRabbit

  • 신규 기능

    • 다양한 사기 유형을 분류하고 위험도를 평가하는 사기 분석 API가 추가되었습니다.
    • 메시지, 키워드, 추가 설명, 이미지 정보를 입력하여 사기 유형을 분석할 수 있습니다.
    • 사기 분석 결과로 분류된 사기 유형, 주요 키워드, 설명, 위험 점수가 제공됩니다.
    • 사기 분석을 위한 예시 데이터와 프롬프트가 추가되어 분류 정확도가 향상되었습니다.
  • 환경 설정

    • OpenAI GPT API 연동을 위한 환경 변수와 설정 파일이 추가되었습니다.
    • GPT API 키가 배포 워크플로우에 안전하게 통합되었습니다.
    • 관련 라이브러리 및 의존성이 업데이트되었습니다.
  • 버그 수정 및 기타

    • 기존 사기 분석 GET 엔드포인트가 제거되었습니다.
    • 라우팅 경로 및 태그 표기가 하이픈으로 일관성 있게 개선되었습니다.

@coderabbitai
Copy link

coderabbitai bot commented Jul 26, 2025

"""

Walkthrough

GPT API 연동을 위한 주요 백엔드 기능이 추가되었습니다. FastAPI 엔드포인트, 서비스 레이어, 프롬프트 생성, 예시 데이터, 설정 관리, 모델 정의 등이 신규로 도입되었고, 배포 워크플로와 의존성도 보강되었습니다. 기존 라우터는 삭제 및 경로가 변경되었습니다.

Changes

파일/경로 변경 요약
.coderabbit/config.yml features.docstrings 설정을 false로 명시한 신규 구성 파일 추가
.github/workflows/deploy.yml 배포 워크플로에 GPT_API_KEY 환경 변수 추가 및 Docker에 전달
app/api/fraud_analysis.py GPT API 연동 POST 엔드포인트 및 예외 처리 신설
app/config/setting.py 환경 변수 기반 설정 클래스 및 인스턴스 추가
app/main.py fraud_analysis 라우터 경로 및 태그를 하이픈 표기로 변경, import 경로 수정
app/models/fraud_request.py FraudRequest Pydantic 모델(4개 필드) 신규 추가
app/models/fraud_response.py FraudResponse Pydantic 모델(4개 필드) 신규 추가
app/prompts/fraud_example.py FraudExample Pydantic 모델(5개 필드) 신규 추가
app/prompts/data/fraud_examples.py 60~70개 유형의 사기 예시 데이터 리스트(FRAUD_EXAMPLES) 신규 추가
app/prompts/fraud_prompts.py 사기 분류 프롬프트 생성 함수 및 예시 포맷팅 함수 추가
app/routers/fraud_analysis.py 기존 GET 방식 라우터 파일 삭제
app/services/gpt_service.py OpenAI GPT API 호출 비동기 함수 및 예외 처리 신설
requirements.txt click 제거, openai, pydantic-settings 등 신규 패키지 대거 추가

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant FastAPI (fraud_analysis)
    participant GPTService
    participant OpenAI API

    Client->>FastAPI (fraud_analysis): POST /api/fraud-analysis (FraudRequest)
    FastAPI (fraud_analysis)->>GPTService: call_gpt(request)
    GPTService->>OpenAI API: GPT-4o-mini 모델로 프롬프트 요청
    OpenAI API-->>GPTService: JSON 응답 반환
    GPTService-->>FastAPI (fraud_analysis): FraudResponse 파싱/반환
    FastAPI (fraud_analysis)-->>Client: FraudResponse 반환
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~18 minutes

Poem

🥕
새싹처럼 자라난 코드 한 줄,
사기 잡는 토끼의 용감한 출근길!
프롬프트와 모델, 예시 데이터도
GPT API와 힘을 합쳐
오늘은 사기꾼도 달아나네—
토끼는 깡총, 리뷰는 순항!
🌱
"""

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38b06f6 and e190004.

📒 Files selected for processing (6)
  • app/api/fraud_analysis.py (1 hunks)
  • app/models/fraud_request.py (1 hunks)
  • app/models/fraud_response.py (1 hunks)
  • app/prompts/fraud_prompts.py (1 hunks)
  • app/services/gpt_service.py (1 hunks)
  • requirements.txt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • app/api/fraud_analysis.py
  • app/services/gpt_service.py
  • requirements.txt
  • app/models/fraud_response.py
  • app/prompts/fraud_prompts.py
  • app/models/fraud_request.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: deploy
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#8/connect-gpt-api

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (8)
app/models/fraud_request.py (1)

8-8: imageContent 필드에 대한 검증 추가를 고려하세요.

imageContent가 문자열로 정의되어 있지만 base64 인코딩된 이미지 데이터인지 URL인지 명확하지 않습니다. 적절한 검증을 추가하는 것을 권장합니다.

from pydantic import BaseModel, Field, validator
from typing import List, Optional
import base64

class FraudRequest(BaseModel):
    messageContent: str
    keywords: List[str]
    additionalDescription: Optional[str] = None
-    imageContent: Optional[str] = None
+    imageContent: Optional[str] = Field(None, description="Base64 encoded image or image URL")
+    
+    @validator('imageContent')
+    def validate_image_content(cls, v):
+        if v and not (v.startswith('data:image/') or v.startswith('http')):
+            # Check if it's valid base64
+            try:
+                base64.b64decode(v)
+            except Exception:
+                raise ValueError('imageContent must be base64 encoded image, data URL, or HTTP URL')
+        return v
.coderabbit/config.yml (1)

1-2: 파일 끝에 개행 문자를 추가하세요.

YAML 파일의 모범 사례에 따라 파일 끝에 개행 문자가 필요합니다.

features:
-  docstrings: false
+  docstrings: false
+
.github/workflows/deploy.yml (1)

64-64: 파일 끝에 개행 문자를 추가하세요.

YAML 파일의 모범 사례에 따라 파일 끝에 개행 문자가 필요합니다.

              -e GPT_API_KEY="${{ env.GPT_API_KEY }}" \
-              ${{ env.DOCKER_REPO }}:latest
+              ${{ env.DOCKER_REPO }}:latest
+
app/config/setting.py (1)

9-9: 설정 인스턴스 초기화 시 예외 처리 고려

환경변수가 누락되거나 잘못된 경우를 대비한 예외 처리를 추가하는 것이 좋습니다.

다음과 같이 개선할 수 있습니다:

-settings = Settings()
+try:
+    settings = Settings()
+except Exception as e:
+    raise RuntimeError(f"설정 초기화 실패: {e}")
app/models/fraud_response.py (1)

1-1: 사용하지 않는 import 제거

conint가 import되었지만 사용되지 않습니다.

-from pydantic import BaseModel, conint
+from pydantic import BaseModel, Field, validator
app/prompts/fraud_example.py (1)

4-9: 필드 검증 및 문서화 개선

현재 모든 필드가 기본 타입으로만 정의되어 있어 검증이 부족합니다. 특히 빈 값이나 잘못된 데이터에 대한 처리가 필요합니다.

다음과 같이 개선할 수 있습니다:

-from pydantic import BaseModel
+from pydantic import BaseModel, Field, validator
 from typing import List
 
 class FraudExample(BaseModel):
-    type_name: str
-    message_content: str
-    keywords: List[str]
-    additional_description: str
-    image_content: str
+    type_name: str = Field(..., min_length=1, description="사기 유형명")
+    message_content: str = Field(..., min_length=1, description="메시지 내용")
+    keywords: List[str] = Field(..., min_items=1, description="키워드 목록")
+    additional_description: str = Field(default="", description="추가 설명")
+    image_content: str = Field(default="", description="이미지 내용")
+    
+    @validator('type_name', 'message_content')
+    def validate_required_fields(cls, v):
+        if not v.strip():
+            raise ValueError('필수 필드는 빈 값일 수 없습니다')
+        return v.strip()
app/services/gpt_service.py (1)

6-8: OpenAI 클라이언트 비동기 초기화 고려

현재 동기 클라이언트를 사용하고 있지만, 비동기 함수에서 사용하므로 AsyncOpenAI를 사용하는 것이 더 적절합니다.

-from openai import OpenAI, OpenAIError
+from openai import AsyncOpenAI, OpenAIError

-client = OpenAI(
+client = AsyncOpenAI(
     api_key = settings.gpt_api_key
     )
app/prompts/fraud_prompts.py (1)

10-10: 대량의 예시 데이터 처리 시 성능을 고려하세요.

기본값으로 FRAUD_EXAMPLES 전체를 사용하고 있는데, 향후 60-70개 예시가 모두 추가되면 토큰 사용량이 크게 증가할 수 있습니다. PR 목표에서도 언급된 우려사항입니다.

예시 개수를 제한하는 매개변수를 추가하는 것을 고려해 보세요:

def get_fraud_detection_prompt(
    message_content: str,
    additional_description: str,
    keywords: List[str],
    image_content: str,
    examples: List[FraudExample] = FRAUD_EXAMPLES,
    max_examples: int = 10  # 예시 개수 제한
) -> List[Dict[str, str]]:
    # 예시 개수 제한 로직 추가
    limited_examples = examples[:max_examples] if max_examples else examples
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db39166 and 218e02f.

📒 Files selected for processing (13)
  • .coderabbit/config.yml (1 hunks)
  • .github/workflows/deploy.yml (2 hunks)
  • app/api/fraud_analysis.py (1 hunks)
  • app/config/setting.py (1 hunks)
  • app/main.py (1 hunks)
  • app/models/fraud_request.py (1 hunks)
  • app/models/fraud_response.py (1 hunks)
  • app/prompts/data/fraud_examples.py (1 hunks)
  • app/prompts/fraud_example.py (1 hunks)
  • app/prompts/fraud_prompts.py (1 hunks)
  • app/routers/fraud_analysis.py (0 hunks)
  • app/services/gpt_service.py (1 hunks)
  • requirements.txt (1 hunks)
💤 Files with no reviewable changes (1)
  • app/routers/fraud_analysis.py
🧰 Additional context used
🧬 Code Graph Analysis (5)
app/main.py (1)
app/api/fraud_analysis.py (1)
  • fraud_analysis (13-20)
app/services/gpt_service.py (2)
app/models/fraud_request.py (1)
  • FraudRequest (4-8)
app/prompts/fraud_prompts.py (1)
  • get_fraud_detection_prompt (5-52)
app/prompts/data/fraud_examples.py (1)
app/prompts/fraud_example.py (1)
  • FraudExample (4-9)
app/api/fraud_analysis.py (3)
app/services/gpt_service.py (1)
  • call_gpt (10-32)
app/models/fraud_request.py (1)
  • FraudRequest (4-8)
app/models/fraud_response.py (1)
  • FraudResponse (4-8)
app/prompts/fraud_prompts.py (1)
app/prompts/fraud_example.py (1)
  • FraudExample (4-9)
🪛 YAMLlint (1.37.1)
.coderabbit/config.yml

[error] 2-2: no new line character at the end of file

(new-line-at-end-of-file)

.github/workflows/deploy.yml

[error] 64-64: no new line character at the end of file

(new-line-at-end-of-file)

🪛 Ruff (0.12.2)
app/services/gpt_service.py

28-28: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

app/models/fraud_response.py

1-1: pydantic.conint imported but unused

Remove unused import: pydantic.conint

(F401)

app/api/fraud_analysis.py

20-20: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🪛 GitHub Actions: CI/CD pipeline test
requirements.txt

[error] 4-4: pip install failed: No matching distribution found for click==8.2.1. The required version requires Python >=3.10 but the environment uses Python 3.9.

🔇 Additional comments (10)
app/main.py (2)

2-2: LGTM! 모듈 구조 개선이 잘 반영되었습니다.

app.routers에서 app.api로의 import 경로 변경이 새로운 프로젝트 구조를 잘 반영하고 있습니다.


7-7: LGTM! REST API 명명 규칙을 준수합니다.

라우터 prefix와 tag에서 언더스코어를 하이픈으로 변경한 것이 REST API 모범 사례를 잘 따르고 있습니다.

requirements.txt (1)

3-22: 검증 결과: 모든 새 패키지는 Python 3.9와 호환됩니다.

  • certifi
  • distro
  • dotenv
  • httpcore
  • httpx
  • jiter
  • openai
  • pydantic-settings
  • tqdm

위 패키지들 모두 Python 3.9에서 요구사항 오류 없이 설치 가능함을 확인했습니다.
따라서 추가 조치는 필요하지 않습니다.

.github/workflows/deploy.yml (2)

17-17: LGTM! API 키 보안 처리가 적절합니다.

GitHub Secrets를 통한 GPT API 키 관리가 보안 모범 사례를 잘 따르고 있습니다.


60-64: LGTM! Docker 컨테이너에 환경 변수 전달이 올바릅니다.

Docker run 명령어에서 환경 변수를 안전하게 전달하는 방식이 적절합니다.

app/prompts/data/fraud_examples.py (2)

5-28: 사기 예시 데이터 구조가 잘 설계되었습니다.

각 사기 유형별로 적절한 예시 데이터가 제공되고 있으며, 한국어 컨텍스트에 맞는 현실적인 사기 시나리오를 반영하고 있습니다. 키워드와 추가 설명이 프롬프트 엔지니어링에 유용한 컨텍스트를 제공할 것으로 보입니다.


27-27: 데이터 완성도 확인이 필요합니다.

주석에서 언급된 18개 유형 × 34개 예시 (총 6070개 항목)가 아직 완성되지 않은 상태입니다.

전체 데이터셋 완성 계획과 타임라인을 확인해 주세요. 현재 3개 예시만으로는 GPT 모델의 성능이 제한될 수 있습니다.

app/prompts/fraud_prompts.py (3)

5-11: 함수 시그니처가 잘 설계되었습니다.

매개변수 타입 힌트와 기본값 설정이 적절하며, 반환 타입도 명확하게 정의되어 있습니다.


13-28: 시스템 프롬프트가 명확하고 구체적입니다.

JSON 출력 형식을 명시하고 한국어로 명확한 지시사항을 제공하고 있어 GPT 모델이 일관된 응답을 생성할 수 있을 것으로 보입니다.


54-68: 예시 데이터 포맷팅 로직이 효율적입니다.

build_example_lines 함수가 예시 데이터를 일관된 형식으로 변환하고 있으며, JSON 예시도 포함하여 모델의 이해를 돕고 있습니다.

Comment on lines 14 to 20
try:
answer = await call_gpt(request)
response = FraudResponse.model_validate_json(answer)
return response

except Exception as e:
raise HTTPException(status_code=500, detail=f"사기분석 실패: {e}")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

예외 처리 및 오류 로깅 개선 필요

현재 예외 처리에서 원본 예외 정보가 손실되고, 로깅이 없어 디버깅이 어렵습니다. 또한 JSON 파싱 실패와 GPT API 호출 실패를 구분하여 처리하는 것이 좋습니다.

다음과 같이 개선할 수 있습니다:

+import logging
+
+logger = logging.getLogger(__name__)
+
 async def fraud_analysis(request: FraudRequest):
     try:
         answer = await call_gpt(request)
+        logger.info(f"GPT 응답 수신: {len(answer)} 글자")
+    except Exception as e:
+        logger.error(f"GPT API 호출 실패: {e}", exc_info=True)
+        raise HTTPException(status_code=500, detail=f"GPT API 호출 실패: {e}") from e
+    
+    try:
         response = FraudResponse.model_validate_json(answer)
         return response
-        
     except Exception as e:
-        raise HTTPException(status_code=500, detail=f"사기분석 실패: {e}")
+        logger.error(f"응답 파싱 실패: {e}, 원본 응답: {answer}", exc_info=True)
+        raise HTTPException(status_code=500, detail=f"응답 파싱 실패: {e}") from e
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try:
answer = await call_gpt(request)
response = FraudResponse.model_validate_json(answer)
return response
except Exception as e:
raise HTTPException(status_code=500, detail=f"사기분석 실패: {e}")
import logging
logger = logging.getLogger(__name__)
async def fraud_analysis(request: FraudRequest):
try:
answer = await call_gpt(request)
logger.info(f"GPT 응답 수신: {len(answer)} 글자")
except Exception as e:
logger.error(f"GPT API 호출 실패: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"GPT API 호출 실패: {e}") from e
try:
response = FraudResponse.model_validate_json(answer)
return response
except Exception as e:
logger.error(f"응답 파싱 실패: {e}, 원본 응답: {answer}", exc_info=True)
raise HTTPException(status_code=500, detail=f"응답 파싱 실패: {e}") from e
🧰 Tools
🪛 Ruff (0.12.2)

20-20: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🤖 Prompt for AI Agents
In app/api/fraud_analysis.py around lines 14 to 20, the current exception
handling loses the original error details and lacks logging, making debugging
difficult. Improve this by adding proper logging of the caught exceptions and
differentiate between JSON parsing errors and GPT API call failures using
separate except blocks. This will help provide clearer error context and
maintain the original exception information in the HTTPException detail.

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
gpt_api_key: str
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

API 키 필드에 대한 검증 강화 필요

API 키는 필수 필드이므로 명시적으로 설정하고 기본값을 제거하는 것이 좋습니다. 또한 빈 문자열 검증도 추가해야 합니다.

다음과 같이 개선할 수 있습니다:

+from pydantic import Field, validator
+
 class Settings(BaseSettings):
-    gpt_api_key: str
+    gpt_api_key: str = Field(..., min_length=1, description="OpenAI GPT API 키")
+    
+    @validator('gpt_api_key')
+    def validate_api_key(cls, v):
+        if not v or not v.strip():
+            raise ValueError('API 키는 필수입니다')
+        return v.strip()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
gpt_api_key: str
from pydantic import Field, validator
class Settings(BaseSettings):
gpt_api_key: str = Field(..., min_length=1, description="OpenAI GPT API 키")
@validator('gpt_api_key')
def validate_api_key(cls, v):
if not v or not v.strip():
raise ValueError('API 키는 필수입니다')
return v.strip()
🤖 Prompt for AI Agents
In app/config/setting.py at line 4, the gpt_api_key field currently lacks
validation and a default value. To fix this, explicitly mark gpt_api_key as a
required field without a default and add validation to ensure it is not an empty
string. This will enforce that the API key must be provided and cannot be empty.

Comment on lines 4 to 8
class FraudRequest(BaseModel):
messageContent: str
keywords: List[str]
additionalDescription: str
imageContent: str No newline at end of file
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

필드 검증 및 선택적 필드 고려가 필요합니다.

현재 모든 필드가 필수로 설정되어 있어 API 사용성이 제한될 수 있습니다. 특히 additionalDescriptionimageContent는 선택적으로 만드는 것을 고려해보세요.

from pydantic import BaseModel
from typing import List
+from typing import Optional

class FraudRequest(BaseModel):
    messageContent: str
    keywords: List[str]
-    additionalDescription: str
-    imageContent: str
+    additionalDescription: Optional[str] = None
+    imageContent: Optional[str] = None
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class FraudRequest(BaseModel):
messageContent: str
keywords: List[str]
additionalDescription: str
imageContent: str
from pydantic import BaseModel
from typing import List
from typing import Optional
class FraudRequest(BaseModel):
messageContent: str
keywords: List[str]
additionalDescription: Optional[str] = None
imageContent: Optional[str] = None
🤖 Prompt for AI Agents
In app/models/fraud_request.py around lines 4 to 8, all fields in the
FraudRequest model are currently required, which limits API usability. Modify
the model to make additionalDescription and imageContent optional by using
typing.Optional and providing default values such as None. Also, consider adding
validation to ensure required fields are properly checked while allowing these
two fields to be omitted.

Comment on lines 4 to 8
class FraudResponse(BaseModel):
estimatedFraudType: str # 분류된 사기 유형
keywords: List[str] # 주요 위험 키워드 (최대 3개)
explanation: str # 해당 유형으로 판단한 이유
score: float # 위험도(0~100) No newline at end of file
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

필드 검증 로직 강화 필요

주요 필드들에 대한 검증이 부족합니다. 특히 score는 0-100 범위여야 하고, keywords는 최대 3개로 제한되어야 합니다.

다음과 같이 검증을 추가할 수 있습니다:

 class FraudResponse(BaseModel):
     estimatedFraudType: str                  # 분류된 사기 유형
-    keywords: List[str]              # 주요 위험 키워드 (최대 3개)
+    keywords: List[str] = Field(..., min_items=1, max_items=3, description="주요 위험 키워드 (최대 3개)")
     explanation: str                      # 해당 유형으로 판단한 이유
-    score: float                  # 위험도(0~100)
+    score: float = Field(..., ge=0, le=100, description="위험도(0~100)")
+    
+    @validator('estimatedFraudType')
+    def validate_fraud_type(cls, v):
+        if not v.strip():
+            raise ValueError('사기 유형은 필수입니다')
+        return v.strip()
+    
+    @validator('explanation')
+    def validate_explanation(cls, v):
+        if not v.strip():
+            raise ValueError('설명은 필수입니다')
+        return v.strip()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class FraudResponse(BaseModel):
estimatedFraudType: str # 분류된 사기 유형
keywords: List[str] # 주요 위험 키워드 (최대 3개)
explanation: str # 해당 유형으로 판단한 이유
score: float # 위험도(0~100)
class FraudResponse(BaseModel):
estimatedFraudType: str # 분류된 사기 유형
keywords: List[str] = Field(
...,
min_items=1,
max_items=3,
description="주요 위험 키워드 (최대 3개)"
)
explanation: str # 해당 유형으로 판단한 이유
score: float = Field(
...,
ge=0,
le=100,
description="위험도(0~100)"
)
@validator('estimatedFraudType')
def validate_fraud_type(cls, v):
if not v.strip():
raise ValueError('사기 유형은 필수입니다')
return v.strip()
@validator('explanation')
def validate_explanation(cls, v):
if not v.strip():
raise ValueError('설명은 필수입니다')
return v.strip()
🤖 Prompt for AI Agents
In app/models/fraud_response.py around lines 4 to 8, the FraudResponse model
lacks validation for key fields. Add validation to ensure the score field is
constrained between 0 and 100, and limit the keywords list to a maximum of 3
items. Use Pydantic validators or field constraints to enforce these rules,
raising appropriate errors if the conditions are not met.

Comment on lines 18 to 32
try:
response = client.responses.create(
model="gpt-4o-mini",
input = messages,
temperature = 0.5, # 생성된 텍스트의 무작위성을 결정
max_output_tokens = 200
)
print(response)

except OpenAIError as e:
raise RuntimeError(f"GPT API 호출 실패: {e}")
except Exception as e:
return f"서버 오류 발생: {e}"

return response.output_text.strip()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

OpenAI API 호출 방식 및 예외 처리 수정 필요

현재 코드에서 여러 가지 중요한 문제가 있습니다:

  1. client.responses.create는 올바른 OpenAI API 메서드가 아닙니다
  2. 응답 객체의 output_text 속성도 존재하지 않습니다
  3. 예외 처리에서 원본 예외 정보가 손실됩니다
  4. 프로덕션 코드에 디버깅용 print문이 남아있습니다

다음과 같이 수정해야 합니다:

+import logging
+
+logger = logging.getLogger(__name__)
+
 async def call_gpt(request: FraudRequest):
     messages = get_fraud_detection_prompt(
         message_content = request.messageContent, 
         additional_description = request.additionalDescription,
         keywords = request.keywords,
         image_content = request.imageContent
     )
     
     try:
-        response = client.responses.create(
+        response = await client.chat.completions.create(
             model="gpt-4o-mini",
-            input = messages,
+            messages=messages,
             temperature = 0.5, # 생성된 텍스트의 무작위성을 결정
-            max_output_tokens = 200
+            max_tokens=200
         )
-        print(response)
+        logger.info(f"GPT API 호출 성공, 사용 토큰: {response.usage}")
         
     except OpenAIError as e:
-        raise RuntimeError(f"GPT API 호출 실패: {e}")
+        logger.error(f"GPT API 호출 실패: {e}", exc_info=True)
+        raise RuntimeError(f"GPT API 호출 실패: {e}") from e
     except Exception as e:
-        return f"서버 오류 발생: {e}"
+        logger.error(f"예상치 못한 서버 오류: {e}", exc_info=True)
+        raise RuntimeError(f"서버 오류 발생: {e}") from e

-    return response.output_text.strip()
+    return response.choices[0].message.content.strip()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try:
response = client.responses.create(
model="gpt-4o-mini",
input = messages,
temperature = 0.5, # 생성된 텍스트의 무작위성을 결정
max_output_tokens = 200
)
print(response)
except OpenAIError as e:
raise RuntimeError(f"GPT API 호출 실패: {e}")
except Exception as e:
return f"서버 오류 발생: {e}"
return response.output_text.strip()
import logging
logger = logging.getLogger(__name__)
async def call_gpt(request: FraudRequest):
messages = get_fraud_detection_prompt(
message_content=request.messageContent,
additional_description=request.additionalDescription,
keywords=request.keywords,
image_content=request.imageContent
)
try:
response = await client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
temperature=0.5, # 생성된 텍스트의 무작위성을 결정
max_tokens=200
)
logger.info(f"GPT API 호출 성공, 사용 토큰: {response.usage}")
except OpenAIError as e:
logger.error(f"GPT API 호출 실패: {e}", exc_info=True)
raise RuntimeError(f"GPT API 호출 실패: {e}") from e
except Exception as e:
logger.error(f"예상치 못한 서버 오류: {e}", exc_info=True)
raise RuntimeError(f"서버 오류 발생: {e}") from e
return response.choices[0].message.content.strip()
🧰 Tools
🪛 Ruff (0.12.2)

28-28: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🤖 Prompt for AI Agents
In app/services/gpt_service.py around lines 18 to 32, the code incorrectly uses
client.responses.create which is not a valid OpenAI API method, and attempts to
access a non-existent output_text attribute on the response. Additionally, the
exception handling loses original error details and there is a leftover print
statement. To fix this, replace client.responses.create with the correct method
for chat completions (e.g., client.chat.completions.create), access the
generated text from the proper response field (like
response.choices[0].message.content), remove the print statement, and update
exception handling to preserve and propagate original error information
properly.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 218e02f and 38b06f6.

📒 Files selected for processing (1)
  • requirements.txt (1 hunks)
🔇 Additional comments (1)
requirements.txt (1)

13-13: 이슈 없음: 구버전 OpenAI API 호출 패턴 미발견
전역 검색 결과 openai.ChatCompletion.create 또는 openai.Completion.create 호출이 모두 발견되지 않았습니다. 따라서 1.x API 마이그레이션이 완료된 것으로 확인됩니다.

@chaeyuuu
Copy link
Contributor

수고하셨습니다.!! 최대한 토큰 적게 쓰는 방식으로 잘 학습시키는 방법을 찾아봐야할거같네융..

@yeonju73 yeonju73 merged commit 4040389 into main Jul 26, 2025
3 checks passed
@yeonju73 yeonju73 deleted the feat/#8/connect-gpt-api branch July 26, 2025 11:17
@coderabbitai coderabbitai bot mentioned this pull request Aug 12, 2025
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] GPT API 연결

2 participants