User Feedback Loop 설계 및 개발 - 100-hours-a-week/12-marong-Wiki GitHub Wiki
preference_update.py
를 통해 사용자가 좋아요를 누른 데이터를 기반으로 장소 선호 벡터 업데이트
for user_id in user_ids:
chroma_user_id = f"user_{user_id}"
print(f"Processing user_id: {user_id} with chroma_user_id: {chroma_user_id}")
vibe_doc = vibelikes_collection.get(ids=[chroma_user_id], include=["embeddings"])
menu_doc = menulikes_collection.get(ids=[chroma_user_id], include=["embeddings"])
start, end = get_last_week_range()
# 별도 선호 벡터가 없는 경우 기본 값은 영벡터
vibe_embed_vector = np.zeros(768)
menu_embed_vector = np.zeros(768)
if len(vibe_doc["embeddings"]) > 0:
vibe_embed_vector = np.array(vibe_doc["embeddings"][0])
if len(menu_doc["embeddings"]) > 0:
menu_embed_vector = np.array(menu_doc["embeddings"][0])
...
- Backend DB 기반으로 지난 주 장소에 대해 좋아요를 누른 사용자를 조회하여 별도 장소 선호 벡터가 없는 경우 기본 값은 영벡터로 부여
- Chroma DB에서 벡터가 조회되는 경우 해당 벡터가 유저의 장소, 메뉴 선호 벡터
- 사용자가 좋아요를 누른 장소의 상호명을 바탕으로
review_collection
,menu_collection
에서 임베딩 벡터 조회
분기 처리를 통해 MySQL의 Transaction과 유사하게 업데이트 과정 안정성 강화
condition1 = (len(review_result["embeddings"]) > 0 and len(vibe_like_history["ids"]) == 0)
condition2 = (len(menu_result["embeddings"]) > 0 and len(menu_like_history["ids"]) == 0)
# print(f"Processing place: {place_name}, conditions: {condition1}, {condition2}")
if condition1 and condition2:
vibe_vec = np.array(review_result["embeddings"][0])
menu_vec = np.array(menu_result["embeddings"][0])
...
- 리뷰 컬렉션과 메뉴 컬렉션 모두에서 해당 **상호명(place_name)**에 대한 임베딩 벡터가 조회되어야 함
- 사용자가 해당 장소에 대해 리뷰 또는 메뉴 좋아요 기록이 없는 경우에만, 아래 벡터가 업데이트됨:
장소 분위기 선호 벡터
메뉴 선호 벡터
- 업데이트 방식: → 각 임베딩 벡터의 **10% 비중(weight)**을 반영하여 선호 벡터에 누적
# 변화량 출력
def safe_cosine_similarity(a, b):
norm_a = np.linalg.norm(a)
norm_b = np.linalg.norm(b)
if norm_a == 0 or norm_b == 0:
return None
return np.dot(a, b) / (norm_a * norm_b)
def l2_distance(a, b):
return np.linalg.norm(a - b)
vibe_cos = safe_cosine_similarity(original_vibe_vector, vibe_embed_vector)
menu_cos = safe_cosine_similarity(original_menu_vector, menu_embed_vector)
vibe_l2 = l2_distance(original_vibe_vector, vibe_embed_vector)
menu_l2 = l2_distance(original_menu_vector, menu_embed_vector)
print(f"[user_id: {user_id}] vibe_cos_sim={vibe_cos if vibe_cos is not None else '값 없음'}, vibe_l2={vibe_l2:.4f}")
print(f"[user_id: {user_id}] menu_cos_sim={menu_cos if menu_cos is not None else '값 없음'}, menu_l2={menu_l2:.4f}")
- 선호 벡터는
RecommendPlace
추천 클래스 객체의 속성으로 초기화되어 추천 로직에 반영됨 - 향후 Chroma DB에서 검색 시 유저의 선호 벡터가 없는 경우 더미 벡터인 영벡터로 초기화, 선호 벡터가 있는 경우 이를 유저의 임베딩 벡터로 반환