Agent 2.0 exdev 서버 배포 스택
- server-dev start/stop/deploy 및 Gitea push 자동 배포 - local-dev 로컬 개발 환경 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
"""
|
||||
의도 감지 모듈
|
||||
──────────────
|
||||
사용자 질문의 의도를 분류 (인사, 종료, 불만, 일반 등)
|
||||
"""
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class Intent:
|
||||
"""의도 분류 결과"""
|
||||
name: str # "greeting", "farewell", "general"
|
||||
confidence: float # 0.0 ~ 1.0
|
||||
matched_keywords: List[str] # 매칭된 키워드
|
||||
|
||||
def is_special(self) -> bool:
|
||||
"""특별 처리가 필요한 의도인지 (인사, 종료만)"""
|
||||
return self.name in ["greeting", "farewell"]
|
||||
|
||||
|
||||
class IntentDetector:
|
||||
"""사용자 의도 감지기"""
|
||||
|
||||
# 의도별 키워드 패턴
|
||||
INTENT_PATTERNS = {
|
||||
"greeting": {
|
||||
"keywords": [
|
||||
"안녕", "안녕하세요", "안녕하십니까",
|
||||
"처음", "반가", "반갑습니다",
|
||||
"hi", "hello", "hey",
|
||||
"처음 뵙겠습니다", "처음입니다"
|
||||
],
|
||||
"priority": 1 # 우선순위 (낮을수록 높음)
|
||||
},
|
||||
"farewell": {
|
||||
"keywords": [
|
||||
"감사", "고마워", "고맙습니다", "감사합니다",
|
||||
"잘됐", "해결", "알겠", "알았",
|
||||
"끝", "종료", "그만",
|
||||
"bye", "goodbye", "끝내", "닫기",
|
||||
"도움 됐", "도움됐", "충분"
|
||||
],
|
||||
"priority": 2
|
||||
}
|
||||
# complaint 제거: 감정 분석(EmotionDetector)으로만 처리
|
||||
}
|
||||
|
||||
def detect(self, query: str, ts: Optional[str] = None) -> Intent:
|
||||
"""의도 감지
|
||||
|
||||
Args:
|
||||
query: 사용자 질문
|
||||
ts: 타임스탬프 (로깅용)
|
||||
|
||||
Returns:
|
||||
Intent 객체
|
||||
"""
|
||||
query_lower = query.lower().strip()
|
||||
|
||||
# 빈 문자열 체크
|
||||
if not query_lower:
|
||||
return Intent(name="general", confidence=1.0, matched_keywords=[])
|
||||
|
||||
# 각 의도별 매칭 점수 계산
|
||||
intent_scores = {}
|
||||
|
||||
for intent_name, config in self.INTENT_PATTERNS.items():
|
||||
matched = []
|
||||
for keyword in config["keywords"]:
|
||||
if keyword.lower() in query_lower:
|
||||
matched.append(keyword)
|
||||
|
||||
if matched:
|
||||
# 매칭된 키워드 개수와 우선순위를 고려한 점수
|
||||
score = len(matched) * (1.0 / config["priority"])
|
||||
intent_scores[intent_name] = {
|
||||
"score": score,
|
||||
"matched": matched,
|
||||
"priority": config["priority"]
|
||||
}
|
||||
|
||||
# 매칭된 의도가 없으면 일반 질문
|
||||
if not intent_scores:
|
||||
return Intent(name="general", confidence=1.0, matched_keywords=[])
|
||||
|
||||
# 가장 높은 점수의 의도 선택
|
||||
best_intent = max(intent_scores.items(), key=lambda x: x[1]["score"])
|
||||
intent_name = best_intent[0]
|
||||
intent_data = best_intent[1]
|
||||
|
||||
# 신뢰도 계산 (0.7 ~ 0.95)
|
||||
confidence = min(0.95, 0.7 + (intent_data["score"] * 0.1))
|
||||
|
||||
result = Intent(
|
||||
name=intent_name,
|
||||
confidence=confidence,
|
||||
matched_keywords=intent_data["matched"]
|
||||
)
|
||||
|
||||
if ts:
|
||||
print(f"[IntentDetector] {ts} 의도 감지: {result.name} (신뢰도: {result.confidence:.2f}, 키워드: {result.matched_keywords})")
|
||||
|
||||
return result
|
||||
|
||||
def is_greeting(self, query: str) -> bool:
|
||||
"""인사 여부 판단 (간단한 헬퍼)"""
|
||||
intent = self.detect(query)
|
||||
return intent.name == "greeting"
|
||||
|
||||
def is_farewell(self, query: str) -> bool:
|
||||
"""종료 인사 여부 판단"""
|
||||
intent = self.detect(query)
|
||||
return intent.name == "farewell"
|
||||
Reference in New Issue
Block a user