멋사 부트캠프

[Project - Howru] (4) 채팅 NLP 기반 사용자 추천 시스템 구현

sagecode 2025. 8. 20. 15:24

NLP Tagging Service를 별도의 모듈로 구현했습니다.

  • 이 서비스는 MSA 아키텍처에서 “사용자 관심사 분석기” 역할을 담당합니다.
fastapi-api/
 ├── analysisTag.py       # NLP 태깅 서비스 메인 코드
 ├── Dockerfile           # 컨테이너 실행 환경
 ├── requirements.txt     # 의존성 패키지
 └── fastapi-api.iml      # IDE 설정 파일

왜 MSA로 분리했는가?

  • 확장성: NLP 연산은 자원 소모가 크기 때문에 별도의 서비스로 분리하여 독립적으로 확장 가능
  • 독립 배포: Dockerfile 기반으로 채팅 서비스, 알림 서비스와 분리해 배포 가능
  • 데이터 분리: MongoDB에 독립 컬렉션을 사용
  • 유연성: 새로운 태그/키워드 추가 시 이 모듈만 수정하면 전체 서비스에 영향 없음

analysisTag.py

FastAPI 초기화 & 헬스체크

app = FastAPI(title="NLP Tagging Service")

@app.get("/health")
def health():
    return {"ok": True}

 

MongoDB 연결

MONGO_URI = os.getenv("MONGO_URI", "mongodb+srv://...")  
MONGO_DB  = os.getenv("MONGO_DB", "howrudb")

client = MongoClient(MONGO_URI, ...)
db = client[MONGO_DB]

 

태그 정의

tag_descriptions = {
    "TRAVEL": "Travel & Tourism: travel, trip, vacation, ...",
    "FOOD": "Food & Cooking: recipe, meal, ingredient, ...",
    ...
}
tag_keywords = {
    "TRAVEL": ["travel", "trip", "tour", "beach", "passport"],
    "FOOD": ["food", "cooking", "recipe", "chef", "ingredient"],
    ...
}

 

NLP 임베딩 모델 로딩

model = SentenceTransformer("all-MiniLM-L6-v2")
tag_embeddings = {tag: model.encode(desc, convert_to_tensor=True)
                  for tag, desc in tag_descriptions.items()}

 

  • 사전학습된 SentenceTransformer 사용
  • 태그 설명을 임베딩 벡터로 변환 → 나중에 단어와 유사도 비교

분류 로직

 

# ===== 분류 로직 =====
def classify_word(word: str, threshold=0.2, top_k=3):
    # 키워드 직접 매칭
    for tag, keywords in tag_keywords.items():
        if word.lower() in (kw.lower() for kw in keywords):
            return [(tag, 1.0)]

    wv = model.encode(word, convert_to_tensor=True)
    sims = [(tag, float(util.cos_sim(wv, tv).item())) for tag, tv in tag_embeddings.items()]
    sims.sort(key=lambda x: x[1], reverse=True)
    weights = [1.0, 0.5, 0.25]
    out = []
    for i, (tag, s) in enumerate(sims[:top_k]):
        if s >= threshold:
            out.append((tag, s * weights[i]))
    return out

def classify_words(words: List[str]) -> Dict[str, float]:
    agg = {tag: 0.0 for tag in tag_descriptions.keys()}
    for w in words:
        for tag, sc in classify_word(w):
            agg[tag] += sc
    return {k: round(v, 4) for k, v in agg.items() if v > 0}​

 

서비스 아키텍처 상 위치

[Chat Service]  →  [NLP Tagging Service]  →  [Recommendation Service]

이렇게 태깅된 결과를 가지고 spring server에서 사용자를 추천하게 된다.