[DOCX 3종 생성 (UTF-8, 편집 가능)] - 01_소프트웨어_저작권_등록_신청서.docx (37KB) 한국저작권위원회 제출용 / 맑은 고딕 / 색상 섹션 - 02_소프트웨어사업자_신고서.docx (37KB) 과학기술정보통신부/KOSA 제출용 - 03_조달청_나라장터_물품_등록_신청서.docx (38KB) 공공기관 납품용 나라장터 등록 [generate_docx.py 특징] - python-docx 기반 (한글 UTF-8 완전 지원) - 검정 박스 없음 (맑은 고딕 직접 적용) - 편집 가능: Word / 한글(HWP) / LibreOffice - 섹션별 색상 배너 (파란/빨간/주황 테마) - 서명란, 첨부서류, 수수료 안내 포함 [certification/source/ 저작권 등록용 소스코드] - 01_core_ssh_agentless.py (450줄) - 에이전트리스 SSH 핵심 - 02_core_license_engine.py (455줄) - AES-256-GCM 라이선스 - 03_router_sr_management.py(501줄) - SR 관리 API - 04_core_ai_classifier.py (90줄) - AI 티켓 분류 - 05_frontend_dashboard.js (200줄) - 대시보드 프론트 - README.md - 제출 안내 및 독창성 설명 - 모든 파일: 영업비밀(암호화키) 마스킹 처리 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
91 lines
3.3 KiB
Python
91 lines
3.3 KiB
Python
"""AI 자동 티켓 분류 — SR 타이틀/설명에서 우선순위, 카테고리, 담당팀 제안."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
CLASSIFY_PROMPT = """다음 IT 서비스 요청을 분석하여 JSON으로 분류하세요.
|
|
|
|
제목: {title}
|
|
설명: {description}
|
|
|
|
다음 필드를 포함하는 JSON만 출력하세요:
|
|
{{
|
|
"priority": "CRITICAL|HIGH|MEDIUM|LOW",
|
|
"category": "HARDWARE|SOFTWARE|NETWORK|DATABASE|SECURITY|DEPLOYMENT|OTHER",
|
|
"team": "INFRA|DEV|DBA|SECURITY|HELPDESK",
|
|
"urgency_reason": "우선순위 판단 이유",
|
|
"keywords": ["핵심키워드1", "핵심키워드2", "핵심키워드3"],
|
|
"confidence": 0.85
|
|
}}"""
|
|
|
|
|
|
async def classify_ticket(title: str, description: str) -> dict:
|
|
"""SR 제목과 설명으로 AI 분류 제안 생성."""
|
|
prompt = CLASSIFY_PROMPT.format(
|
|
title=title,
|
|
description=(description or "")[:500],
|
|
)
|
|
|
|
try:
|
|
from core.llm_client import get_llm_client
|
|
client = get_llm_client()
|
|
resp = await client.chat(prompt)
|
|
raw = resp.content.strip()
|
|
if "```" in raw:
|
|
raw = raw.split("```")[1]
|
|
if raw.startswith("json"):
|
|
raw = raw[4:]
|
|
result = json.loads(raw)
|
|
# 필수 필드 보정
|
|
result.setdefault("priority", "MEDIUM")
|
|
result.setdefault("category", "OTHER")
|
|
result.setdefault("team", "HELPDESK")
|
|
result.setdefault("urgency_reason", "")
|
|
result.setdefault("keywords", [])
|
|
result.setdefault("confidence", 0.5)
|
|
return result
|
|
except Exception as e:
|
|
logger.warning("AI 티켓 분류 실패 (Fail-Safe): %s", e)
|
|
# 키워드 기반 규칙 폴백
|
|
return _rule_based_classify(title, description)
|
|
|
|
|
|
def _rule_based_classify(title: str, description: str) -> dict:
|
|
"""LLM 실패 시 키워드 규칙 기반 분류."""
|
|
text = f"{title} {description}".lower()
|
|
priority = "MEDIUM"
|
|
category = "OTHER"
|
|
team = "HELPDESK"
|
|
|
|
if any(k in text for k in ["긴급", "critical", "서비스 중단", "장애", "접속 불가"]):
|
|
priority = "CRITICAL"
|
|
elif any(k in text for k in ["오류", "error", "실패", "배포", "deploy"]):
|
|
priority = "HIGH"
|
|
elif any(k in text for k in ["설치", "변경", "업그레이드"]):
|
|
priority = "MEDIUM"
|
|
|
|
if any(k in text for k in ["서버", "cpu", "메모리", "디스크", "하드웨어"]):
|
|
category, team = "HARDWARE", "INFRA"
|
|
elif any(k in text for k in ["db", "데이터베이스", "oracle", "mysql", "postgresql"]):
|
|
category, team = "DATABASE", "DBA"
|
|
elif any(k in text for k in ["네트워크", "방화벽", "포트", "ip", "dns"]):
|
|
category, team = "NETWORK", "INFRA"
|
|
elif any(k in text for k in ["보안", "취약점", "cve", "패치"]):
|
|
category, team = "SECURITY", "SECURITY"
|
|
elif any(k in text for k in ["배포", "deploy", "jenkins", "빌드"]):
|
|
category, team = "DEPLOYMENT", "DEV"
|
|
elif any(k in text for k in ["소프트웨어", "애플리케이션", "app", "버그"]):
|
|
category, team = "SOFTWARE", "DEV"
|
|
|
|
return {
|
|
"priority": priority,
|
|
"category": category,
|
|
"team": team,
|
|
"urgency_reason": "키워드 규칙 기반 분류 (LLM 미사용)",
|
|
"keywords": [],
|
|
"confidence": 0.3,
|
|
}
|