feat: AI 서비스 및 AI 어시스턴트 전용 페이지 추가
- ai-service: Ollama 기반 AI 서비스 (분류, 시맨틱 검색, RAG Q&A, 패턴 분석) - AI 어시스턴트 페이지: 채팅형 Q&A, 시맨틱 검색, 패턴 분석, 분류 테스트 - 권한 시스템에 ai_assistant 페이지 등록 (기본 비활성) - 기존 페이지에 AI 기능 통합 (대시보드, 수신함, 관리함) - docker-compose, gateway, nginx 설정 업데이트 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -879,14 +879,81 @@ function showError(message) {
|
||||
alert(message);
|
||||
}
|
||||
|
||||
// API 스크립트 동적 로딩
|
||||
const script = document.createElement('script');
|
||||
script.src = '/static/js/api.js?v=20260213';
|
||||
script.onload = function() {
|
||||
console.log('API 스크립트 로드 완료 (issues-inbox.html)');
|
||||
initializeInbox();
|
||||
};
|
||||
script.onerror = function() {
|
||||
console.error('API 스크립트 로드 실패');
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
// AI 분류 추천
|
||||
async function aiClassifyCurrentIssue() {
|
||||
if (!currentIssueId || typeof AiAPI === 'undefined') return;
|
||||
const issue = issues.find(i => i.id === currentIssueId);
|
||||
if (!issue) return;
|
||||
|
||||
const btn = document.getElementById('aiClassifyBtn');
|
||||
const loading = document.getElementById('aiClassifyLoading');
|
||||
const result = document.getElementById('aiClassifyResult');
|
||||
if (btn) btn.disabled = true;
|
||||
if (loading) loading.classList.remove('hidden');
|
||||
if (result) result.classList.add('hidden');
|
||||
|
||||
// RAG 강화 분류 사용 (과거 사례 참고)
|
||||
const classifyFn = AiAPI.classifyWithRAG || AiAPI.classifyIssue;
|
||||
const data = await classifyFn(
|
||||
issue.description || issue.final_description || '',
|
||||
issue.detail_notes || ''
|
||||
);
|
||||
|
||||
if (loading) loading.classList.add('hidden');
|
||||
if (btn) btn.disabled = false;
|
||||
|
||||
if (!data.available) {
|
||||
if (result) {
|
||||
result.innerHTML = '<p class="text-xs text-red-500">AI 서비스를 사용할 수 없습니다</p>';
|
||||
result.classList.remove('hidden');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const categoryMap = {
|
||||
'material_missing': '자재 누락',
|
||||
'design_error': '설계 오류',
|
||||
'incoming_defect': '반입 불량',
|
||||
'inspection_miss': '검사 누락',
|
||||
};
|
||||
const deptMap = {
|
||||
'production': '생산',
|
||||
'quality': '품질',
|
||||
'purchasing': '구매',
|
||||
'design': '설계',
|
||||
'sales': '영업',
|
||||
};
|
||||
|
||||
const cat = data.category || '';
|
||||
const dept = data.responsible_department || '';
|
||||
const severity = data.severity || '';
|
||||
const summary = data.summary || '';
|
||||
const confidence = data.category_confidence ? Math.round(data.category_confidence * 100) : '';
|
||||
|
||||
result.innerHTML = `
|
||||
<div class="space-y-1">
|
||||
<p><strong>분류:</strong> ${categoryMap[cat] || cat} ${confidence ? `(${confidence}%)` : ''}</p>
|
||||
<p><strong>부서:</strong> ${deptMap[dept] || dept}</p>
|
||||
<p><strong>심각도:</strong> ${severity}</p>
|
||||
${summary ? `<p><strong>요약:</strong> ${summary}</p>` : ''}
|
||||
<button onclick="applyAiClassification('${cat}')"
|
||||
class="mt-2 px-3 py-1 bg-purple-600 text-white text-xs rounded hover:bg-purple-700">
|
||||
<i class="fas fa-check mr-1"></i>적용
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
result.classList.remove('hidden');
|
||||
}
|
||||
|
||||
function applyAiClassification(category) {
|
||||
const reviewCategory = document.getElementById('reviewCategory');
|
||||
if (reviewCategory && category) {
|
||||
reviewCategory.value = category;
|
||||
}
|
||||
if (window.showToast) {
|
||||
window.showToast('AI 추천이 적용되었습니다', 'success');
|
||||
}
|
||||
}
|
||||
|
||||
// 초기화 (api.js는 HTML에서 로드됨)
|
||||
initializeInbox();
|
||||
|
||||
Reference in New Issue
Block a user