Skip to content

feat: 추천 일정에 Gemini AI 한 줄 맥락 해설 추가 - #119

Merged
kokkumong merged 3 commits into
devfrom
feature/118-gemini-schedule-insight
Jun 15, 2026
Merged

feat: 추천 일정에 Gemini AI 한 줄 맥락 해설 추가#119
kokkumong merged 3 commits into
devfrom
feature/118-gemini-schedule-insight

Conversation

@kokkumong

Copy link
Copy Markdown
Collaborator

🚀 작업 내용 (What)

  • 추천 시간 결과 화면에 Gemini AI 한 줄 맥락 해설 카드 추가 ("Gemini AI" 배지 + 한국어 한 문장)
  • src/lib/gemini/insight.ts: Gemini REST(generateContent) 직접 호출 클라이언트. 키 미설정·호출 실패·타임아웃(8초) 시 null 반환(SDK 의존성 없음)
  • GET /api/schedules/[id]/insight: 집계 결과(추천 시간 + 참여자 가용시간)로 해설을 생성하는 라우트
  • ScheduleRoomClient: 추천 시간 목록 위에 해설 카드 렌더링, 추천 시간 변경 시 재요청
  • .env.example: GEMINI_MODEL(선택, 기본 gemini-2.5-flash) 문서화

📣 핵심 변경 이유 (Why)

  • 추천된 시간이 좋은지 자연어로 설명해 결과의 설득력과 사용성을 높입니다.
  • 부가 기능이므로 API 키 미설정·생성 실패 시 카드를 숨겨 핵심 결과 화면은 그대로 동작합니다(graceful degradation).

📸 스크린샷 (Visuals, 선택)

⚠️ 체크리스트 (Checklist)

  • 브랜치 컨벤션(feature/00-name)을 지켰나요?
  • 커밋 컨벤션(feat:, fix: 등)을 지켰나요?
  • 작업 전에 관련 이슈를 생성하고 연결했나요?
  • 내 코드가 팀의 기존 코드를 망가뜨리지 않았는지 확인했나요? (추가 only, tsc·lint 통과)

🔗 관련 이슈 (Issue)

Close #118

모임 일정 취합 결과(추천 시간 + 참여자 가용시간)를 Gemini로 요약해
"왜 이 시간이 좋은지" 설명하는 한국어 한 문장 해설을 결과 화면에 노출한다.

- src/lib/gemini/insight.ts: Gemini REST(generateContent) 직접 호출 클라이언트.
  키 미설정·실패·타임아웃 시 null 반환(graceful degradation, SDK 의존성 없음)
- src/app/api/schedules/[id]/insight: 집계 결과로 해설을 생성하는 GET 라우트
- ScheduleRoomClient: 추천 시간 위에 "Gemini AI" 배지 해설 카드 렌더링
- .env.example: GEMINI_MODEL(선택, 기본 gemini-2.5-flash) 문서화

Close #118

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
moim-app Ready Ready Preview, Comment Jun 15, 2026 1:09am

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kokkumong, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 46 minutes and 2 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a684a974-aaf0-4ea0-ae52-fa344499f6a8

📥 Commits

Reviewing files that changed from the base of the PR and between b746a1e and 2efafbc.

📒 Files selected for processing (2)
  • src/app/schedule/[id]/ScheduleRoomClient.tsx
  • src/lib/gemini/insight.ts

Walkthrough

Gemini API를 사용해 추천 일정에 한국어 한 줄 해설을 생성하는 기능을 추가한다. src/lib/gemini/insight.ts에 타입·프롬프트 빌더·API 호출 함수를 새로 작성하고, GET /api/schedules/[id]/insight 엔드포인트를 신설한다. HostResultPanel에서 엔드포인트를 fetch해 결과를 조건부로 렌더링하며, API 키 미설정·호출 실패 시 카드를 숨긴다.

Changes

Gemini AI 일정 해설 기능

Layer / File(s) Summary
Gemini 인사이트 라이브러리
src/lib/gemini/insight.ts
InsightParticipant, ScheduleInsightInput 인터페이스 정의. formatHour/formatSlot/buildPrompt/normalizeInsight 유틸 추가. generateScheduleInsight에서 AbortController 8초 타임아웃, 응답 실패·예외 시 null 폴백 처리.
GET /api/schedules/[id]/insight 라우트
src/app/api/schedules/[id]/insight/route.ts, .env.example
nodejs runtime + force-dynamic 설정. 일정 미존재 시 404, commonSlots 없으면 { insight: null }, 있으면 generateScheduleInsight 호출 후 { insight } 반환. .env.exampleGEMINI_MODEL 주석 예시 추가.
HostResultPanel 인사이트 UI
src/app/schedule/[id]/ScheduleRoomClient.tsx
Sparkles 아이콘 임포트, insight 상태 선언, useEffect에서 /api/schedules/${id}/insight fetch 및 취소 처리. insight 존재 시에만 Gemini AI 해설 카드 조건부 렌더링.

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

feature

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 'feat:' 접두어로 시작하며, 추가된 주요 기능인 Gemini AI 기반 일정 해설 기능을 명확하게 설명한다.
Description check ✅ Passed PR 설명이 템플릿 구조를 충실히 따르며, 작업 내용(What), 핵심 변경 이유(Why), 체크리스트, 관련 이슈를 모두 포함했다.
Linked Issues check ✅ Passed 코드 변경사항이 #118의 모든 요구사항을 충족한다: Gemini API 클라이언트 구현, 해설 생성 API 라우트, UI 렌더링, graceful degradation, 환경변수 설정.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #118의 범위 내에 있으며, 추가 기능만 포함되어 있고 기존 핵심 로직 수정이 없다.

✏️ 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 feature/118-gemini-schedule-insight

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.

- gemini-2.5+ thinking 모델이 출력 토큰을 추론에 소비해 한 줄 해설이
  잘리던 문제 수정: thinkingConfig.thinkingBudget=0으로 thinking 비활성화,
  maxOutputTokens 120→256 상향
- GEMINI_API_KEY 앞뒤 공백/개행 trim 처리(붙여넣기 실수 방어)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 `@src/app/api/schedules/`[id]/insight/route.ts:
- Around line 32-40: Replace the actual participant names being sent to the
Gemini API with ordinal-based pseudonyms to minimize personal information
exposure to external services. In the participants array mapping within the
generateScheduleInsight call, instead of passing p.name directly, substitute it
with a pseudonym (such as "Participant 1", "Participant 2", etc.) based on each
participant's index position in the array. This preserves the context needed for
insight generation while preventing real names from being transmitted to and
logged by the external Google API service.

In `@src/app/schedule/`[id]/ScheduleRoomClient.tsx:
- Around line 1124-1144: The useEffect dependency array in
ScheduleRoomClient.tsx only tracks schedule.id and commonSlotsCount, but it
should use actual slot content instead of just the count, so that recommendation
changes are detected even if the count remains the same. Additionally, when the
fetch fails or returns null data, the previous insight value is not cleared,
causing stale explanations to remain visible. To fix this: change the dependency
array from [schedule.id, commonSlotsCount] to include a content-based key or
hash of the actual commonSlots data to properly track changes, and explicitly
call setInsight(null) both at the start of the effect (before the fetch) and in
the catch block to ensure stale insights are always cleared when the request
fails or returns invalid data.

In `@src/lib/gemini/insight.ts`:
- Around line 135-139: The error logging in the Gemini API response handling
block is exposing potentially sensitive data from the API response body (such as
participant names and available times from the prompt) to server logs. Remove
the response body retrieval and logging to address the privacy concern.
Specifically, eliminate the line that calls response.text() to capture the
response body details, and update the console.error call to only include the
response status code for error reporting, matching the consistency of error
handling elsewhere in the function (such as at lines 152 and 154 where other
errors are logged without response body details).
- Around line 99-133: The generateScheduleInsight function has two issues: (1)
it directly accesses process.env and calls fetch, making it untestable for error
paths and timeouts, and (2) it likely logs detailed API error responses which
exposes sensitive information like quota and auth state. To fix this, refactor
the function to accept optional dependency parameters (for environment variables
like apiKey and model, and for the fetch implementation) with defaults that
preserve current behavior, allowing tests to inject mock implementations.
Additionally, change error logging to record only the HTTP status code instead
of the full API response body, reducing information disclosure risk while
maintaining debugging capability.
🪄 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 Plus

Run ID: a2c2f68a-7f54-4901-9759-e18107bdad88

📥 Commits

Reviewing files that changed from the base of the PR and between 5171f8d and b746a1e.

📒 Files selected for processing (4)
  • .env.example
  • src/app/api/schedules/[id]/insight/route.ts
  • src/app/schedule/[id]/ScheduleRoomClient.tsx
  • src/lib/gemini/insight.ts

Comment thread src/app/api/schedules/[id]/insight/route.ts
Comment thread src/app/schedule/[id]/ScheduleRoomClient.tsx Outdated
Comment thread src/lib/gemini/insight.ts
Comment thread src/lib/gemini/insight.ts Outdated
- insight 해설 stale 방지: 추천 슬롯 내용 기반 키로 재요청, 요청 시작/실패 시
  setInsight(null)로 초기화, AbortController로 중복 요청 취소
- generateScheduleInsight에 의존성 주입(fetcher/apiKey/model) 추가해 단위 테스트 용이화
- Gemini 에러 응답 본문 로깅 제거(참여자명·가용시간 로그 유출 방지), 상태코드만 기록

참여자 실명은 이름 멘트가 기능 핵심이고 결과 링크에서 이미 공개되는 값이라 의도적으로 유지.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kokkumong
kokkumong merged commit 2ffffcf into dev Jun 15, 2026
5 checks passed
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.

[FEAT] 추천 일정에 Gemini AI 한 줄 맥락 해설 추가

1 participant