Files
youlbot/services/db/user_profile_repository.py
T
shinalok 06bcdb03ac Implement Phase 4~14: LangGraph Agent, RAG pipeline, Gradio Web UI, voice interface
- Upgrade LLM to Qwen3-14B-4bit with Thinking mode (MlxChatModel as LangChain BaseChatModel)
- Add LangGraph ReAct agent with tool calling loop (search_documents, web_search, get_current_date, remember/recall_user_info)
- Add RAG pipeline: BAAI/bge-m3 embeddings + Qdrant vector store + semantic chunking (SemanticSplitter via cosine similarity)
- Replace fixed-size RecursiveCharacterTextSplitter with meaning-based SemanticSplitter (numpy only, no extra deps)
- Add Gradio Web UI (app.py): chat, document ingestion, document management tabs
- Add multi-user support (user_id isolation in DB + per-user agent cache + dropdown selector)
- Add conversation history restore from MySQL on agent init (Phase 11)
- Add UserProfileRepository for persistent user profile (remember/recall tools)
- Add thread-local DB connections to fix pymysql thread-safety with LangGraph ToolNode
- Add Phase 14 voice interface: Whisper STT (microphone → text) + macOS TTS (say -v Yuna)
- Enforce search_documents-first policy in system prompt and tool descriptions
- Update ROADMAP2.md: Phase 14 완료, Phase 13 청킹 부분 완료

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 14:06:22 +09:00

32 lines
1.2 KiB
Python

from __future__ import annotations
from services.db.mysql_service import DatabaseService
class UserProfileRepository:
"""td_user_profile 테이블을 통한 사용자 장기 메모리 저장소."""
def __init__(self, db: DatabaseService):
self._db = db
def remember(self, key: str, value: str, user_id: str = "default") -> None:
self._db.execute_write(
"""INSERT INTO td_user_profile (user_id, key_name, value)
VALUES (%s, %s, %s)
ON DUPLICATE KEY UPDATE value = VALUES(value), updated_at = NOW()""",
(user_id, key, value),
)
def recall(self, key: str, user_id: str = "default") -> str | None:
rows = self._db.execute(
"SELECT value FROM td_user_profile WHERE user_id = %s AND key_name = %s",
(user_id, key),
)
return rows[0]["value"] if rows else None
def get_all(self, user_id: str = "default") -> dict[str, str]:
rows = self._db.execute(
"SELECT key_name, value FROM td_user_profile WHERE user_id = %s ORDER BY updated_at",
(user_id,),
)
return {r["key_name"]: r["value"] for r in rows}