Files
hyungi_document_server/frontend/src/lib/utils/isQuestion.ts
T
Hyungi Ahn f4791cfada feat(ui): Phase D.1~D.4 — 검색 페이지 이드 답변 통합
D.1: documents route 디자인 토큰 정리 (var(--*) → 시맨틱 토큰, 잔여 0)
D.2: isQuestion 질문형 감지 유틸 (? 단일단어 허용, 한/영 6규칙)
D.3: AskAnswerCard 컴팩트 답변 카드 + analyze.ts 타입 정의
D.4: 질문형 검색 시 /search/ask 병렬 호출 + 상단 카드 배치

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 11:09:58 +09:00

62 lines
2.1 KiB
TypeScript

/**
* 검색 쿼리가 "질문형"인지 판별 (규칙 기반).
* true이면 검색 결과 페이지에서 /api/search/ask 병렬 호출.
*
* false positive: /ask가 refused=true 반환하면 카드 숨김 → 무해.
* false negative: 기존 검색 결과만 표시 → 무해.
*/
export function isQuestion(q: string): boolean {
const trimmed = q.trim();
if (trimmed.length === 0) return false;
// 1. ?로 끝나면 단일 단어라도 허용 (왜?, 절차?)
if (trimmed.endsWith('?')) return true;
// ? 없으면 단일 단어 / 4자 미만 제외 (키워드 보호)
if (trimmed.length < 4) return false;
if (trimmed.split(/\s+/).length < 2) return false;
// 2. 한국어 질문 어미
const KO_ENDINGS = [
'인가요', '인가', '인지', '있나요', '있나',
'할까요', '할까', '될까요', '될까',
'뭐야', '뭔가', '뭘까', '뭔지', '뭐지', '뭐죠',
'는지', '은지', '일까',
'어때', '어떤가',
'됩니까', '합니까', '입니까', '나요', '까요',
'주세요', '알려줘', '설명해', '비교해',
];
for (const ending of KO_ENDINGS) {
if (trimmed.endsWith(ending)) return true;
}
// 3. 한국어 질문 시작어
const KO_STARTS = [
'어떻게', '왜', '무엇', '무슨', '뭐가', '누가',
'어디', '언제', '몇', '얼마나', '어떤', '어느',
];
for (const start of KO_STARTS) {
if (trimmed.startsWith(start)) return true;
}
// 4. 영어 질문 시작어 (대소문자 무시)
const EN_STARTS = [
'what', 'how', 'why', 'when', 'where', 'who', 'which',
'is', 'are', 'do', 'does', 'can', 'could', 'should', 'would',
'explain', 'describe', 'compare', 'tell me',
];
const lower = trimmed.toLowerCase();
for (const start of EN_STARTS) {
if (lower.startsWith(start + ' ')) return true;
}
// 5. 의미 패턴 (끝 단어)
const SEMANTIC_ENDINGS = ['차이', '비교', '설명', '요약', '정리', '방법', '절차'];
const lastWord = trimmed.split(/\s+/).pop() || '';
for (const pat of SEMANTIC_ENDINGS) {
if (lastWord === pat || lastWord.endsWith(pat)) return true;
}
return false;
}