guardia-messenger/hooks/useSmartNotif.ts

54 lines
1.8 KiB
TypeScript

/**
* useSmartNotif (#28) — AI 스마트 알림 필터링 훅
*
* 알림 수신 시 Ollama로 긴급도 판단 → urgent=false면 묵음 처리.
* 반환된 filter() 함수로 알림 큐를 필터링/표시 제어.
*
* 보안: 온프레미스 Ollama만 사용. 알림 본문에 자격증명 미포함 가정.
*/
import { useCallback } from 'react'
import { generateJSON, DEFAULT_TEXT_MODEL } from '../lib/ollama'
interface NotifVerdict {
urgent: boolean
reason: string
}
const SAFE_DEFAULT: NotifVerdict = { urgent: true, reason: 'AI 판단 불가 — 기본 표시' }
export function useSmartNotif() {
/** 단일 알림 긴급도 판단. Ollama 미가동 시 안전하게 urgent=true. */
const judge = useCallback(async (alertText: string): Promise<NotifVerdict> => {
if (!alertText?.trim()) return SAFE_DEFAULT
const prompt =
`다음 ITSM 알림이 즉시 대응이 필요한 긴급 알림인지 판단하세요: "${alertText}". ` +
`JSON으로만 출력: {"urgent": true 또는 false, "reason": "한국어 한 줄 사유"}`
return generateJSON<NotifVerdict>(DEFAULT_TEXT_MODEL, prompt, SAFE_DEFAULT)
}, [])
/**
* 알림 배열을 긴급한 것만 남기도록 필터링.
* getText: 알림 객체에서 판단용 텍스트 추출.
*/
const filter = useCallback(
async <T>(notifs: T[], getText: (n: T) => string): Promise<T[]> => {
const verdicts = await Promise.all(notifs.map(n => judge(getText(n))))
return notifs.filter((_, i) => verdicts[i].urgent)
},
[judge],
)
/** 단일 알림 표시 여부 (urgent=false면 묵음). */
const shouldShow = useCallback(
async (alertText: string): Promise<boolean> => {
const v = await judge(alertText)
return v.urgent
},
[judge],
)
return { judge, filter, shouldShow }
}
export default useSmartNotif