Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
5a5407a
feat: integrate korean book metadata and UI citations
SanghunYun95 Mar 2, 2026
8a01e1d
fix: apply coderabbit review suggestions
SanghunYun95 Mar 2, 2026
133442a
fix(backend): apply coderabbit review feedback for db and mapping scr…
SanghunYun95 Mar 2, 2026
43d1722
fix(backend): address additional coderabbit PR inline comments
SanghunYun95 Mar 2, 2026
0dd84a4
refactor(backend): use shared env parser and HTTPS for API
SanghunYun95 Mar 3, 2026
3057ad7
fix(backend): allow key rotation for all errors in book mapping
SanghunYun95 Mar 3, 2026
fc24774
feat: implement dynamic chat title and dynamic philosopher highlighting
SanghunYun95 Mar 3, 2026
cdbc817
fix: apply CodeRabbit PR review feedback
SanghunYun95 Mar 3, 2026
6c7566d
fix(pr): address CodeRabbit review feedback on backend tools and DB s…
SanghunYun95 Mar 3, 2026
78fc51a
chore: resolve merge conflicts
SanghunYun95 Mar 3, 2026
9de894d
fix(pr): address additional CodeRabbit comments
SanghunYun95 Mar 3, 2026
3d773d7
style: update welcome messages and input placeholder to be more gener…
SanghunYun95 Mar 3, 2026
4335bee
fix(pr): address additional CodeRabbit feedback for title truncation …
SanghunYun95 Mar 3, 2026
7298aac
UI: Remove redundant buttons (useful, copy, regenerate) from MessageList
SanghunYun95 Mar 3, 2026
30dd215
Merge branch 'main' into feat/book-metadata
SanghunYun95 Mar 3, 2026
ce91d6a
Refactor: apply CodeRabbit review suggestions
SanghunYun95 Mar 3, 2026
0bd1fcd
docs: rewrite README for interviewers
SanghunYun95 Mar 3, 2026
1196e30
docs, refactor: refine README and MessageList observer logic per PR c…
SanghunYun95 Mar 3, 2026
1b31b83
refactor: resolve observer unmount leak, Biome formatting, exhaustive…
SanghunYun95 Mar 3, 2026
e1ec3fc
fix: clear visibleMessages on unmount & use targeted eslint disable
SanghunYun95 Mar 3, 2026
36bd572
docs, refactor: disable philosopher filtering & update README examples
SanghunYun95 Mar 3, 2026
f13f327
refactor: apply PR refinements for mapping script and observers
SanghunYun95 Mar 3, 2026
1a9358b
Merge origin/main into feat/book-metadata (Resolve conflicts)
SanghunYun95 Mar 3, 2026
5d2841d
Fix: apply CodeRabbit feedback for React hooks and Tailwind
SanghunYun95 Mar 3, 2026
2584e3b
Feat: support multiple GEMINI_API_KEYS via comma-separated env var fo…
SanghunYun95 Mar 4, 2026
2395400
Fix: apply PR CodeRabbit round 8 feedback and add favicon
SanghunYun95 Mar 4, 2026
a0f719c
Fix: resolve conflicts and apply PR CodeRabbit round 9 feedback
SanghunYun95 Mar 4, 2026
789bdf4
Fix: apply PR CodeRabbit round 10 feedback
SanghunYun95 Mar 4, 2026
4c33094
Fix: apply PR CodeRabbit round 11 feedback
SanghunYun95 Mar 4, 2026
c9b0b91
Fix: apply PR CodeRabbit round 12 feedback
SanghunYun95 Mar 4, 2026
f24b224
fix(backend): preload models on startup and use async invokes to prev…
SanghunYun95 Mar 4, 2026
622a663
test: update mocks for refactored async llm/embedding functions
SanghunYun95 Mar 4, 2026
9eedd78
fix(pr): address lint, magic numbers, and use favicon for logo
SanghunYun95 Mar 4, 2026
4d878c2
fix(pr): resolve conflicts and add sizes prop to next/image
SanghunYun95 Mar 4, 2026
8495460
fix(backend): load models in background to prevent startup timeout on…
SanghunYun95 Mar 5, 2026
110049b
fix(backend): resolve conflict and apply PR feedback (timeouts, track…
SanghunYun95 Mar 5, 2026
105a59c
fix(backend): add graceful teardown for preload task on shutdown
SanghunYun95 Mar 5, 2026
7d918eb
feat(backend): add /ready endpoint and handle CancelledError in preload
SanghunYun95 Mar 5, 2026
382f90e
fix(backend): handle CancelledError properly in /ready readiness probe
SanghunYun95 Mar 5, 2026
1987897
fix(backend): lazy load ML models in chat routes to avoid Uvicorn sta…
SanghunYun95 Mar 5, 2026
f11491c
fix(backend): add error logging to /ready endpoint for better observa…
SanghunYun95 Mar 5, 2026
cad791b
refactor(backend): use else block for successful return in readiness …
SanghunYun95 Mar 5, 2026
e94fbe2
refactor(backend): use logger.warning in /ready, catch Exception in l…
SanghunYun95 Mar 5, 2026
359511c
Merge branch 'main' into feat/book-metadata and apply lifespan except…
SanghunYun95 Mar 5, 2026
f187cb1
fix: handle zero-chunk LLM responses, add prompt injection defense, a…
SanghunYun95 Mar 5, 2026
95be5fa
fix(backend): use HuggingFace Inference API for embeddings to resolve…
SanghunYun95 Mar 6, 2026
2c0f465
fix(backend): address CodeRabbit PR feedback for llm.py cleanup, chat…
SanghunYun95 Mar 6, 2026
bfe167c
fix: resolve merge conflicts and restore PR feedback fixes
SanghunYun95 Mar 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion backend/app/api/routes/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,19 @@ async def generate_chat_events(request: Request, query: str, history: List[Histo

try:
chunk_count = 0
disconnected = False
async for chunk in get_response_stream_async(context=combined_context, query=english_query, history=formatted_history):
# If client disconnects, stop generating
if await request.is_disconnected():
disconnected = True
break

chunk_count += 1
# Clean up chunk to avoid SSE formatting issues with newlines
chunk_clean = chunk.replace("\n", "\\n")
yield {"event": "content", "data": chunk_clean}

if chunk_count == 0:
if not disconnected and chunk_count == 0:
logger.warning("LLM returned 0 chunks. Sending a fallback message.")
yield {"event": "content", "data": "철학자는 난색을 표하며 서적을 뒤적거립니다. 대신 철학자가 답변을 해줄 만한 다른 질문은 없을까요?"}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Expand Down
1 change: 1 addition & 0 deletions backend/app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Settings(BaseSettings):
# API Keys
GEMINI_API_KEY: str = ""
ALADIN_API_KEY: str = ""
HUGGINGFACEHUB_API_TOKEN: str = ""

# Supabase Settings
SUPABASE_URL: str = ""
Expand Down
2 changes: 1 addition & 1 deletion backend/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def _on_preload_done(task: asyncio.Task):
await asyncio.wait_for(asyncio.shield(preload_task), timeout=3.0)
except asyncio.TimeoutError:
logger.warning("Preload task did not finish before shutdown.")
except Exception as e:
except Exception:
logger.exception("Exception occurred while waiting for preload task during shutdown.")

app = FastAPI(
Expand Down
17 changes: 10 additions & 7 deletions backend/app/services/embedding.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import threading
import logging
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_huggingface import HuggingFaceEndpointEmbeddings
from app.core.config import settings

logger = logging.getLogger(__name__)

Expand All @@ -18,13 +19,15 @@ def embeddings(self):
if self._embeddings is None:
with self._lock:
if self._embeddings is None:
logger.info("Loading local embedding model: %s (HuggingFace)...", MODEL_NAME)
self._embeddings = HuggingFaceEmbeddings(
model_name=MODEL_NAME,
model_kwargs={'device': 'cpu'},
encode_kwargs={'normalize_embeddings': True}
logger.info("Using HuggingFace Inference API for embedding model: %s", MODEL_NAME)
if not settings.HUGGINGFACEHUB_API_TOKEN:
logger.warning("HUGGINGFACEHUB_API_TOKEN is not set. The Inference API might fail if heavily rate-limited.")
self._embeddings = HuggingFaceEndpointEmbeddings(
model=MODEL_NAME,
task="feature-extraction",
huggingfacehub_api_token=settings.HUGGINGFACEHUB_API_TOKEN
)
logger.info("Local embedding model loaded successfully.")
logger.info("HuggingFace Inference API configured successfully.")
return self._embeddings

def _validate_embedding_dimension(self, embedding: list[float]) -> None:
Expand Down
23 changes: 14 additions & 9 deletions backend/app/services/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,20 @@ async def get_response_stream_async(context: str, query: str, history: str = "")
prompt = get_rag_prompt()
chain = prompt | get_llm() | StrOutputParser()
generator = chain.astream({"context": context, "chat_history": history, "query": query})
while True:
try:
chunk = await asyncio.wait_for(generator.__anext__(), timeout=30.0)
yield chunk
except StopAsyncIteration:
break
except asyncio.TimeoutError:
print("LLM stream chunk timed out after 30 seconds.")
raise
try:
while True:
try:
chunk = await asyncio.wait_for(generator.__anext__(), timeout=30.0)
yield chunk
except StopAsyncIteration:
break
except asyncio.TimeoutError:
import logging
logger = logging.getLogger(__name__)
logger.warning(f"LLM stream chunk timed out after 30 seconds. Query: {query}")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

타임아웃 로그에 사용자 질의 원문을 남기지 마세요.

Line 137은 사용자 입력을 그대로 로그에 기록하고 있어 운영 로그에 민감정보가 저장될 수 있습니다. 원문 대신 비식별 정보만 남기도록 바꿔주세요.

🔧 수정 예시
-        logger.warning(f"LLM stream chunk timed out after 30 seconds. Query: {query}")
+        logger.warning("LLM stream chunk timed out after 30 seconds")
📝 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
logger.warning(f"LLM stream chunk timed out after 30 seconds. Query: {query}")
logger.warning("LLM stream chunk timed out after 30 seconds")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/services/llm.py` at line 137, The warning currently logs the raw
user input via logger.warning(f"... Query: {query}"); change it to avoid storing
PII by logging only non-identifying info (e.g., a short hash or metadata).
Replace the f-string that references query with a redacted identifier: compute a
short SHA-256 (or similar) of query (using
hashlib.sha256(query.encode('utf-8')).hexdigest()[:8]) or log query
length/placeholder, and include that hash/id in the logger.warning call instead
of the raw query; ensure you add the hashlib import if you choose hashing and
keep references to the same logger.warning and query variable names.

raise
finally:
await generator.aclose()

title_prompt = PromptTemplate.from_template(
"""주어진 질문을 기반으로 철학적인 대화방 제목을 15자 이내로 지어줘.
Expand Down
1 change: 1 addition & 0 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ pydantic>=2.7.0
pydantic-settings
python-dotenv
langchain-community==0.4.1
langchain-huggingface>=0.1.0
sentence-transformers>=2.2.0,<3.0.0
slowapi>=0.1.9