Skip to content

Feat/book metadata#15

Merged
SanghunYun95 merged 34 commits intomainfrom
feat/book-metadata
Mar 5, 2026
Merged

Feat/book metadata#15
SanghunYun95 merged 34 commits intomainfrom
feat/book-metadata

Conversation

@SanghunYun95
Copy link
Copy Markdown
Owner

@SanghunYun95 SanghunYun95 commented Mar 4, 2026

Summary by CodeRabbit

업데이트

  • 새 기능

    • 애플리케이션 시작 시 모델을 미리 로드하여 응답 속도 개선
  • 버그 수정

    • 번역 요청에 명시적 시간 초과 처리 추가로 안정성 향상
    • 번역 실패 시 사용자 친화적 오류 메시지 제공
  • 스타일

    • 사이드바 프로필 아바타 디자인 개선
    • 철학자 선택 요소의 호버 상호작용 간소화

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 4, 2026

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

Project Deployment Actions Updated (UTC)
philo-rag Ready Ready Preview, Comment Mar 4, 2026 2:30pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5b7d03a2-1ebc-451b-9599-4dc064264b58

📥 Commits

Reviewing files that changed from the base of the PR and between 9eedd78 and 4d878c2.

📒 Files selected for processing (1)
  • frontend/components/sidebar/Sidebar.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/components/sidebar/Sidebar.tsx

📝 Walkthrough

요약

Walkthrough

이 PR은 번역 및 임베딩 호출을 동기 방식에서 비동기 방식으로 변환하고, 타임아웃 처리를 추가하며, 앱 시작 시 모델을 미리 로드하는 라이프사이클 관리자를 도입합니다. 테스트도 새로운 비동기 패턴에 맞게 업데이트됩니다.

Changes

Cohort / File(s) Summary
Backend 서비스 계층
backend/app/services/embedding.py, backend/app/services/llm.py
임베딩 서비스에 비동기 메서드 agenerate_embedding 추가, 임베딩 차원 검증 로직 추가, 번역 함수를 async def get_english_translation으로 변환하여 ainvoke 호출 사용
Backend API 라우트
backend/app/api/routes/chat.py
번역 호출을 asyncio.wait_for로 변경하여 타임아웃 처리 추가, 임베딩 호출을 비동기 agenerate_embedding으로 변경, SSE 에러 이벤트 추가
Backend 애플리케이션 초기화
backend/app/main.py
모델 사전 로드를 위한 비동기 라이프사이클 컨텍스트 매니저 추가, FastAPI 인스턴스에 라이프사이클 파라미터 설정
Backend 테스트
backend/tests/e2e/test_chat_endpoint.py, backend/tests/integration/test_supabase_match.py, backend/tests/unit/test_llm.py
임베딩 모킹 대상을 generate_embedding에서 agenerate_embedding으로 변경, 번역 테스트를 비동기로 변환하여 AsyncMockpytest.mark.asyncio 사용, 비동기 스트리밍 테스트 추가
Frontend 컴포넌트
frontend/components/sidebar/ActivePhilosophers.tsx, frontend/components/sidebar/Sidebar.tsx
체크 아이콘 호버 상태 제거, 그래디언트 오버레이 호버 효과 제거, Sidebar의 아바타 렌더링을 Next.js Image 컴포넌트로 변경
테스트 로그
backend/pytest_log_utf8.txt
Windows 환경 pytest 세션 출력 로그 추가

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • philo-rag#8: 번역 및 임베딩 호출을 비동기로 변환하는 동일한 패턴을 포함하고 있으며, 채팅 라우트와 EmbeddingService의 agenerate_embedding 변경이 겹침
  • philo-rag#3: 임베딩 서비스의 384차원 임베딩 사용 및 비동기 임베딩 검증 로직 추가가 관련됨
  • philo-rag#9: LLM 번역/스트리밍과 임베딩 경로를 비동기로 변환하는 동일한 패턴을 포함하고 있으며, 채팅 엔드포인트 업데이트가 겹침

Poem

🐰 비동기의 춤을 춘다네
스레드는 물러나고 await이 춤을 춘다
시작할 때 모델을 미리 로드하며
타임아웃도 손에 들고
더 빠르고 매끄러운 응답이여 환영하노라 ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning PR 제목이 변경사항의 실제 내용과 맞지 않습니다. 제목은 '책 메타데이터'를 시사하지만 실제 변경사항은 비동기 처리, 임베딩 서비스 최적화, 모델 사전로드 등 인프라 개선입니다. 제목을 변경사항을 정확히 반영하도록 수정하세요. 예: 'Refactor/async embedding and model preloading' 또는 'Refactor/async services and startup optimization'
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/book-metadata

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: 2

🧹 Nitpick comments (2)
frontend/components/sidebar/ActivePhilosophers.tsx (1)

46-46: 그라디언트 오버레이가 항상 보이지 않습니다.

Line 46에서 opacity-0이 고정되어 있어 오버레이가 항상 투명합니다. 지금 상태에선 isActive에 따른 그라디언트 차이가 실제 UI에 반영되지 않습니다. 활성 상태에서 보이게 하거나, 의도적으로 제거할 거면 관련 스타일을 정리하는 편이 좋습니다.

수정 예시
-                                <div className={`absolute inset-0 bg-gradient-to-r ${isActive ? "from-primary/10" : "from-primary/5"} to-transparent opacity-0 transition-opacity`}></div>
+                                <div className={`absolute inset-0 bg-gradient-to-r ${isActive ? "from-primary/10 opacity-100" : "from-primary/5 opacity-0"} to-transparent transition-opacity`}></div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/sidebar/ActivePhilosophers.tsx` at line 46, The gradient
overlay div in ActivePhilosophers uses a hardcoded "opacity-0" so the gradient
never appears; update the class logic on that div (referencing the isActive
prop/variable and the overlay div in ActivePhilosophers) to conditionally set
opacity (e.g., use isActive to choose "opacity-100" vs "opacity-0") or remove
the opacity class entirely and adjust transitions accordingly so the gradient is
actually visible when isActive is true.
backend/app/services/embedding.py (1)

42-49: 동기/비동기 경로의 차원 검증 로직을 공통화하는 것을 권장합니다.

현재 generate_embeddingagenerate_embedding에 동일한 길이 검증이 중복되어 있어, 이후 수정 시 불일치가 생기기 쉽습니다. 검증을 private helper로 묶어두면 유지보수가 쉬워집니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/services/embedding.py` around lines 42 - 49, The two methods
generate_embedding and agenerate_embedding duplicate the embedding-length check;
extract that logic into a private helper (e.g., _validate_embedding_dimension or
_check_embedding_length) that accepts the embedding list and expected dimension
and raises the same ValueError, then call this helper from both
generate_embedding and agenerate_embedding to centralize validation and avoid
future drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/app/api/routes/chat.py`:
- Around line 42-47: Wrap the external translation call
get_english_translation(query) inside asyncio.wait_for with a sensible timeout
(e.g., 5-10s) to prevent SSE from hanging; update the try/except to catch
asyncio.TimeoutError separately (and logger.exception or logger.warning with
context) and yield the same error SSE payload, and keep the existing generic
Exception handler for other failures—modify the block around
get_english_translation in chat route to use asyncio.wait_for(...) and explicit
timeout handling.

In `@backend/app/main.py`:
- Around line 23-25: The except block that catches exceptions during the
pre-load models step currently only logs the error (logger.error(f"Failed to
pre-load models: {e}")) and continues, which delays startup failures to runtime;
change the except handling in the pre-load models section so it fails fast by
either re-raising the caught exception (raise) or terminating startup (e.g.,
sys.exit(1)) after logging, ensuring the error is surfaced immediately;
references to look for: the try/except around the pre-load models logic, the
logger.error call, and the surrounding startup generator that yields.

---

Nitpick comments:
In `@backend/app/services/embedding.py`:
- Around line 42-49: The two methods generate_embedding and agenerate_embedding
duplicate the embedding-length check; extract that logic into a private helper
(e.g., _validate_embedding_dimension or _check_embedding_length) that accepts
the embedding list and expected dimension and raises the same ValueError, then
call this helper from both generate_embedding and agenerate_embedding to
centralize validation and avoid future drift.

In `@frontend/components/sidebar/ActivePhilosophers.tsx`:
- Line 46: The gradient overlay div in ActivePhilosophers uses a hardcoded
"opacity-0" so the gradient never appears; update the class logic on that div
(referencing the isActive prop/variable and the overlay div in
ActivePhilosophers) to conditionally set opacity (e.g., use isActive to choose
"opacity-100" vs "opacity-0") or remove the opacity class entirely and adjust
transitions accordingly so the gradient is actually visible when isActive is
true.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ea234020-cf8a-4396-ba4d-ffa958c5191c

📥 Commits

Reviewing files that changed from the base of the PR and between 33da227 and f24b224.

⛔ Files ignored due to path filters (1)
  • frontend/app/icon.png is excluded by !**/*.png
📒 Files selected for processing (9)
  • README.md
  • backend/app/api/routes/chat.py
  • backend/app/core/env_utils.py
  • backend/app/main.py
  • backend/app/services/embedding.py
  • backend/app/services/llm.py
  • backend/scripts/generate_book_mapping.py
  • frontend/components/chat/MessageList.tsx
  • frontend/components/sidebar/ActivePhilosophers.tsx

Comment thread backend/app/api/routes/chat.py
Comment thread backend/app/main.py Outdated
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.

🧹 Nitpick comments (2)
backend/app/services/embedding.py (1)

29-33: 차원 값 384는 상수로 분리해 관리하는 편이 안전합니다.

Line 29-Line 33의 매직 넘버를 상수화하면 모델 교체 시 검증 로직 누락 위험을 줄일 수 있습니다.

변경 예시
 MODEL_NAME = "sentence-transformers/all-MiniLM-L6-v2"
+EXPECTED_EMBEDDING_DIM = 384
@@
     def _validate_embedding_dimension(self, embedding: list[float]) -> None:
-        if len(embedding) != 384:
+        if len(embedding) != EXPECTED_EMBEDDING_DIM:
             raise ValueError(
-                f"Unexpected embedding dimension: {len(embedding)} (expected 384)"
+                f"Unexpected embedding dimension: {len(embedding)} (expected {EXPECTED_EMBEDDING_DIM})"
             )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/services/embedding.py` around lines 29 - 33, The
_validate_embedding_dimension method uses the magic number 384; define a named
constant (e.g., EMBEDDING_DIMENSION = 384) at the module or class level and
replace the literal in both the len(embedding) comparison and the error message
so the check reads against EMBEDDING_DIMENSION and the raised ValueError reports
EMBEDDING_DIMENSION instead of the hardcoded 384.
backend/app/main.py (1)

14-20: 의도 명시로 린트 경고(ARG001/B018)를 줄여주세요.

Line 14의 미사용 인자와 Line 20의 사이드이펙트-only 표현식은 린트 노이즈를 만들 수 있습니다. 의도를 코드에 명시하면 CI 안정성이 좋아집니다.

변경 예시
-async def lifespan(app: FastAPI):
+async def lifespan(_app: FastAPI):
@@
-        embedding_service.embeddings
+        _ = embedding_service.embeddings
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/main.py` around lines 14 - 20, Rename the unused FastAPI
parameter in the lifespan function to a named throwaway (e.g., _app) to signal
the unused argument and avoid ARG001/B018 lint warnings, and replace the
side-effect-only expression embedding_service.embeddings with an explicit
intentful action: either call get_llm() to instantiate the LLM (e.g., _ =
get_llm()) and explicitly consume the embeddings attribute (e.g., _ =
embedding_service.embeddings) or call a dedicated preload method on
embedding_service if available; target the lifespan function and the symbols
embedding_service.embeddings and get_llm when making these changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@backend/app/main.py`:
- Around line 14-20: Rename the unused FastAPI parameter in the lifespan
function to a named throwaway (e.g., _app) to signal the unused argument and
avoid ARG001/B018 lint warnings, and replace the side-effect-only expression
embedding_service.embeddings with an explicit intentful action: either call
get_llm() to instantiate the LLM (e.g., _ = get_llm()) and explicitly consume
the embeddings attribute (e.g., _ = embedding_service.embeddings) or call a
dedicated preload method on embedding_service if available; target the lifespan
function and the symbols embedding_service.embeddings and get_llm when making
these changes.

In `@backend/app/services/embedding.py`:
- Around line 29-33: The _validate_embedding_dimension method uses the magic
number 384; define a named constant (e.g., EMBEDDING_DIMENSION = 384) at the
module or class level and replace the literal in both the len(embedding)
comparison and the error message so the check reads against EMBEDDING_DIMENSION
and the raised ValueError reports EMBEDDING_DIMENSION instead of the hardcoded
384.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5cf150e1-01e0-4215-9813-98f7873bde40

📥 Commits

Reviewing files that changed from the base of the PR and between f24b224 and 622a663.

📒 Files selected for processing (9)
  • backend/app/api/routes/chat.py
  • backend/app/main.py
  • backend/app/services/embedding.py
  • backend/pytest_log.txt
  • backend/pytest_log_utf8.txt
  • backend/tests/e2e/test_chat_endpoint.py
  • backend/tests/integration/test_supabase_match.py
  • backend/tests/unit/test_llm.py
  • frontend/components/sidebar/ActivePhilosophers.tsx
✅ Files skipped from review due to trivial changes (1)
  • backend/pytest_log_utf8.txt
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/app/api/routes/chat.py
  • frontend/components/sidebar/ActivePhilosophers.tsx

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.

🧹 Nitpick comments (1)
frontend/components/sidebar/Sidebar.tsx (1)

47-48: sizes prop 추가를 권장합니다.

Next.js Image 컴포넌트에서 fill prop을 사용할 때 sizes 속성을 지정하지 않으면, 브라우저가 적절한 이미지 크기를 선택하는 데 필요한 정보가 부족하여 최적화가 제대로 이루어지지 않을 수 있습니다. 고정 크기(40x40px)이므로 명시적으로 지정하는 것이 좋습니다.

♻️ 제안하는 수정
 <div className="h-10 w-10 shrink-0 relative flex items-center justify-center">
-    <Image src="/icon.png" alt="PhiloRAG Logo" fill className="rounded-full object-cover shadow-[0_0_15px_rgba(217,183,74,0.3)] border border-[`#d9b74a`]/30" />
+    <Image src="/icon.png" alt="PhiloRAG Logo" fill sizes="40px" className="rounded-full object-cover shadow-[0_0_15px_rgba(217,183,74,0.3)] border border-[`#d9b74a`]/30" />
 </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/sidebar/Sidebar.tsx` around lines 47 - 48, The Image
component in Sidebar.tsx uses the fill prop inside a fixed 40x40 container
without specifying sizes, which prevents Next.js from selecting the correct
optimized image; update the <Image ... fill ... /> usage (in the Sidebar
component) to include an appropriate sizes attribute—e.g. sizes="40px" or a
responsive rule like sizes="(max-width: 640px) 40px, 40px"—so the browser and
Next.js can pick the correct image source for that 40x40 UI element.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/components/sidebar/Sidebar.tsx`:
- Around line 47-48: The Image component in Sidebar.tsx uses the fill prop
inside a fixed 40x40 container without specifying sizes, which prevents Next.js
from selecting the correct optimized image; update the <Image ... fill ... />
usage (in the Sidebar component) to include an appropriate sizes attribute—e.g.
sizes="40px" or a responsive rule like sizes="(max-width: 640px) 40px, 40px"—so
the browser and Next.js can pick the correct image source for that 40x40 UI
element.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0cb0ec55-1174-4835-88c5-fd49368cf8c2

📥 Commits

Reviewing files that changed from the base of the PR and between 622a663 and 9eedd78.

📒 Files selected for processing (3)
  • backend/app/main.py
  • backend/app/services/embedding.py
  • frontend/components/sidebar/Sidebar.tsx

@SanghunYun95 SanghunYun95 merged commit cba5a56 into main Mar 5, 2026
3 checks passed
This was referenced Mar 5, 2026
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.

1 participant