Skip to content

feat: OpenAI 호출 어댑터 추가#6

Merged
deli-minju merged 2 commits into
developfrom
feat/#4-openai-adapter
May 23, 2026
Merged

feat: OpenAI 호출 어댑터 추가#6
deli-minju merged 2 commits into
developfrom
feat/#4-openai-adapter

Conversation

@deli-minju
Copy link
Copy Markdown
Contributor

@deli-minju deli-minju commented May 20, 2026

📌 작업 요약

  • 요약:
    • AI 서버 내부 OpenAI 호출 adapter 계층 추가
    • OPENAI_ENABLED 환경변수로 OpenAI 실제 호출 활성화 여부 제어
    • 기본값은 OPENAI_ENABLED=false로 두어 기존 rule-based baseline 응답 유지
    • OPENAI_API_KEY, OPENAI_MODEL, OPENAI_BASE_URL, OPENAI_TIMEOUT_SECONDS 환경변수 로딩 추가
    • prompt-preview에서 사용하던 prompt와 response schema를 OpenAI Responses API 호출에 연결
    • OpenAI 설정 누락 시 503, OpenAI 호출/응답 파싱/스키마 검증 실패 시 502 반환
    • OpenAI 실패 원인 추적을 위한 adapter 로그 정책 추가
    • 가정통신문 분석 문서는 노션 명세와 중복되지 않도록 구현 경계 중심으로 정리
  • 관련 이슈: closes [FEAT] AI 서버 OpenAI 호출 어댑터 추가 #4

🌿 브랜치 정보

  • Source: feat/#4-openai-adapter
  • Target: develop (기본)

✅ 체크리스트

  • 브랜치 컨벤션 준수 (feat/refac/hotfix/chore/design/bugfix)
  • 커밋 컨벤션 준수 (feat/fix/refactor/docs/style/chore)
  • self-review 완료
  • 테스트 및 로컬 실행 확인 완료

🧪 테스트 결과

.\.venv\Scripts\python.exe -m ruff check .
# All checks passed!

.\.venv\Scripts\python.exe -m compileall app
# app 모듈 컴파일 확인

# OPENAI_ENABLED=false 기본값에서 /ai/newsletters/analyze가 rule_based_baseline으로 응답하는 것 확인
# OPENAI_ENABLED=true + OPENAI_API_KEY 미설정 시 OpenAIConfigurationError 발생 확인
# OpenAI adapter의 output_text JSON 파싱 동작 확인

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • OpenAI API를 통한 선택적 뉴스레터 분석 기능 추가 (기본값: 비활성)
    • OpenAI 활성화 시 고급 분석 모드, 비활성 시 규칙 기반 분석으로 자동 전환
  • 문서

    • 환경 변수 설정 옵션 추가 (OPENAI_ENABLED, OPENAI_API_KEY, OPENAI_MODEL 등)
    • AI 서버 동작 및 구현 경계에 대한 문서 업데이트

Review Change Stack

@deli-minju deli-minju self-assigned this May 20, 2026
@deli-minju deli-minju added the feat 새로운 기능 추가 작업 label May 20, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Warning

Rate limit exceeded

@deli-minju has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 38 minutes and 31 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a86dbd9c-8554-45d5-a1fb-618dd820dd68

📥 Commits

Reviewing files that changed from the base of the PR and between 3783fcb and f393436.

📒 Files selected for processing (2)
  • app/config.py
  • app/services/openai_adapter.py
📝 Walkthrough

Walkthrough

이 PR은 AI 서버에 선택적 OpenAI API 호출 기능을 추가합니다. 환경변수로 활성화 여부를 제어하며, 활성화 시 OpenAI Responses API를 호출하고, 비활성화 시 기존 규칙 기반 분석을 수행합니다. 예외 처리 및 설정 검증도 함께 구현됩니다.

Changes

OpenAI 통합 및 조건부 실행

Layer / File(s) 요약
OpenAI 설정 및 환경변수 구성
.env.example, app/config.py, docs/env.md
OPENAI_ENABLED, OPENAI_API_KEY, OPENAI_MODEL, OPENAI_BASE_URL, OPENAI_TIMEOUT_SECONDS 환경변수 템플릿을 추가하고, 파싱/기본값 처리 로직 및 OpenAISettings 설정 관리 클래스를 구현합니다.
OpenAI API 어댑터 구현
app/services/openai_adapter.py
OpenAI Responses API 호출, JSON 응답 파싱, 스키마 검증, 그리고 네트워크/파싱 예외를 OpenAIAdapterError/OpenAIConfigurationError로 변환하는 어댑터를 구현합니다.
서비스 및 라우터 통합
app/services/newsletter_extractor.py, app/routers/newsletters.py
analyze_newsletter에서 OPENAI_ENABLED 설정을 확인하여 OpenAI 어댑터 또는 규칙 기반 분석을 조건부로 실행하고, 라우터에서 OpenAI 예외를 503/502 HTTP 상태 코드로 매핑합니다.
설정 및 구현 문서 업데이트
README.md, docs/env.md, docs/newsletter-extraction.md
OpenAI 선택적 호출 모드의 기본 동작, 환경변수 설정, 그리고 AI 서버/백엔드 책임 경계를 문서화합니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • GACHI-Project/GACHI-AI#5: 두 PR 모두 app/services/newsletter_extractor.pyanalyze_newsletter 경로(분석 응답 생성/meta 구성)를 중심으로 변경되며, 이 PR의 OpenAI 모드 분기 및 메타 확장이 PR #5의 분석 API 스펙 위에 직접 적용됩니다.
  • GACHI-Project/GACHI-AI#2: 이 PR이 PR #2에서 도입한 뉴스레터 추출/라우터 구조를 확장하여 get_openai_settings()/OpenAINewsletterAdapter를 통한 선택적 OpenAI 분석을 추가하고 OpenAI 예외를 HTTP 오류로 매핑합니다.

Suggested labels

refactor

Suggested reviewers

  • Hminkyung
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 'feat: OpenAI 호출 어댑터 추가'로 OpenAI adapter 추가라는 주요 변경 사항을 명확하게 요약하고 있습니다.
Description check ✅ Passed PR 설명은 제공된 템플릿의 모든 필수 섹션(요약, 브랜치 정보, 체크리스트, 테스트 결과)을 포함하고 있으며 작업 내용이 충분히 구체적으로 작성되어 있습니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경사항이 #4 이슈의 요구사항을 충족합니다: OpenAI adapter 구조 추가, 환경변수 로딩, 에러 핸들링/로깅 정책, 기존 baseline 유지, OpenAI 호출 활성화 여부 제어가 모두 구현되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #4 이슈 범위 내에 있습니다: .env.example, README, config.py, newsletter_extractor.py, openai_adapter.py, routers/newsletters.py, docs 파일 변경 모두 OpenAI adapter 도입과 직접 관련이 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#4-openai-adapter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/config.py`:
- Around line 12-19: The _read_float function allows non-positive values (<= 0)
to pass through which can cause runtime errors for settings like
OPENAI_TIMEOUT_SECONDS; update _read_float (and any callers that read
OPENAI_TIMEOUT_SECONDS) to validate the parsed float and if it is <= 0 return
the provided default (or clamp to a sensible minimum) instead of returning the
invalid value—specifically, after converting value = float(value) in _read_float
check if value <= 0 and if so return default; apply the same non-positive check
where OPENAI_TIMEOUT_SECONDS is consumed so bad config falls back to the
default.
- Around line 34-36: 환경 변수가 공백 문자열로 들어오는 경우를 막기 위해 os.getenv("OPENAI_API_KEY")
등에서 반환된 값을 strip()으로 정규화하고, strip 결과가 빈 문자열이면 None(또는 기본값)으로 대체하도록 변경하세요; 구체적으로
app/config.py의 api_key, model, base_url 할당부에서 OPENAI_API_KEY, OPENAI_MODEL,
OPENAI_BASE_URL 값을 각각 가져온 뒤 .strip()으로 공백을 제거하고 빈 문자열이면 None 또는 기존
기본("gpt-4o-mini" / "https://api.openai.com/v1")을 사용하도록 처리하면 됩니다.

In `@app/services/openai_adapter.py`:
- Around line 70-75: The current log call in openai_adapter.py exposes response
bodies/model outputs by logging error_body (from exc.read().decode) and
exc.code; change it to avoid printing raw body/model text: log only the status
code and a sanitized error type/message (e.g., exc.code and
exc.__class__.__name__), replace or redact the body content (e.g., mention
"response body redacted" or include a fixed-length hash/placeholder), and ensure
the same change is applied to the other occurrence around the block referenced
at line ~107; update the logger.warning call(s) to remove or mask error_body
while preserving useful diagnostic info.
- Around line 95-99: The loop over response_body needs defensive type checks to
avoid AttributeError when output/content are not the expected list/dict types;
before iterating, ensure response_body.get("output") is a list, each output is a
dict, output.get("content") is a list, and each content is a dict whose "text"
is a non-empty str, then pass that text into self._loads_model_json; skip
non-conforming entries and if no valid text is found raise/return a proper
adapter-level error (convert the potential AttributeError into the adapter's
exception type) so callers get a clear, handled error instead of a 500.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 58863025-d8a2-4b34-b1de-5dae16e16508

📥 Commits

Reviewing files that changed from the base of the PR and between d1ffe14 and 3783fcb.

📒 Files selected for processing (8)
  • .env.example
  • README.md
  • app/config.py
  • app/routers/newsletters.py
  • app/services/newsletter_extractor.py
  • app/services/openai_adapter.py
  • docs/env.md
  • docs/newsletter-extraction.md

Comment thread app/config.py Outdated
Comment thread app/config.py Outdated
Comment thread app/services/openai_adapter.py
Comment thread app/services/openai_adapter.py Outdated
@deli-minju deli-minju requested a review from Hminkyung May 20, 2026 08:02
@deli-minju deli-minju merged commit 6399efe into develop May 23, 2026
3 checks passed
@deli-minju deli-minju deleted the feat/#4-openai-adapter branch May 23, 2026 18:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 새로운 기능 추가 작업

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] AI 서버 OpenAI 호출 어댑터 추가

1 participant