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:
Hyungi Ahn
2026-03-06 09:38:30 +09:00
parent d385ce7ac1
commit b3012b8320
44 changed files with 2914 additions and 53 deletions

View File

@@ -115,6 +115,57 @@
</div>
</div>
<!-- AI 시맨틱 검색 -->
<div class="bg-white rounded-xl shadow-sm p-6 mb-6">
<div class="flex items-center mb-3">
<i class="fas fa-robot text-purple-500 mr-2"></i>
<h3 class="text-sm font-semibold text-gray-700">AI 유사 부적합 검색</h3>
</div>
<div class="flex space-x-2">
<input type="text" id="aiSearchQuery"
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
placeholder="부적합 내용을 자연어로 검색하세요... (예: 볼트 누락, 용접 불량)"
onkeydown="if(event.key==='Enter') aiSemanticSearch()">
<button onclick="aiSemanticSearch()"
class="px-4 py-2 bg-purple-500 text-white rounded-lg hover:bg-purple-600 transition-colors whitespace-nowrap">
<i class="fas fa-search mr-1"></i>AI 검색
</button>
</div>
<div id="aiSearchLoading" class="hidden mt-3 text-center">
<i class="fas fa-spinner fa-spin text-purple-500 mr-1"></i>
<span class="text-sm text-gray-500">AI 검색 중...</span>
</div>
<div id="aiSearchResults" class="hidden mt-3 space-y-2">
<!-- 검색 결과 -->
</div>
<!-- RAG Q&A -->
<div class="mt-4 pt-4 border-t border-gray-200">
<div class="flex items-center mb-2">
<i class="fas fa-comments text-indigo-500 mr-2"></i>
<h4 class="text-sm font-semibold text-gray-700">AI Q&A (과거 사례 기반)</h4>
</div>
<div class="flex space-x-2">
<input type="text" id="aiQaQuestion"
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
placeholder="질문하세요... (예: 최근 자재 누락이 왜 많아?, 용접 불량 해결방법은?)"
onkeydown="if(event.key==='Enter') aiAskQuestion()">
<button onclick="aiAskQuestion()"
class="px-4 py-2 bg-indigo-500 text-white rounded-lg hover:bg-indigo-600 transition-colors whitespace-nowrap">
<i class="fas fa-paper-plane mr-1"></i>질문
</button>
</div>
<div id="aiQaLoading" class="hidden mt-3 text-center">
<i class="fas fa-spinner fa-spin text-indigo-500 mr-1"></i>
<span class="text-sm text-gray-500">과거 사례 분석 중...</span>
</div>
<div id="aiQaResult" class="hidden mt-3 bg-indigo-50 border border-indigo-200 rounded-lg p-4">
<div id="aiQaAnswer" class="text-sm text-gray-700 whitespace-pre-line"></div>
<div id="aiQaSources" class="mt-2 text-xs text-indigo-500"></div>
</div>
</div>
</div>
<!-- 프로젝트 선택 및 필터 -->
<div class="bg-white rounded-xl shadow-sm p-6 mb-6">
<div class="flex flex-col md:flex-row md:items-center md:justify-between space-y-4 md:space-y-0">
@@ -549,15 +600,29 @@
</div>
</div>
<!-- AI 이슈 상세 모달 -->
<div id="aiIssueModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center" onclick="if(event.target===this)this.classList.add('hidden')">
<div class="bg-white rounded-xl shadow-2xl w-full max-w-lg mx-4 max-h-[80vh] overflow-y-auto">
<div class="sticky top-0 bg-white border-b px-5 py-3 flex justify-between items-center rounded-t-xl">
<h3 id="aiIssueModalTitle" class="font-bold text-gray-800"></h3>
<button onclick="document.getElementById('aiIssueModal').classList.add('hidden')" class="text-gray-400 hover:text-gray-600">
<i class="fas fa-times"></i>
</button>
</div>
<div id="aiIssueModalBody" class="p-5 text-sm text-gray-700 space-y-3"></div>
</div>
</div>
<!-- 스크립트 -->
<script src="/static/js/core/permissions.js?v=20260213"></script>
<script src="/static/js/components/common-header.js?v=20260213"></script>
<script src="/static/js/core/page-manager.js?v=20260213"></script>
<script src="/static/js/core/auth-manager.js?v=20260213"></script>
<script src="/static/js/utils/issue-helpers.js?v=20260213"></script>
<script src="/static/js/utils/photo-modal.js?v=20260213"></script>
<script src="/static/js/utils/toast.js?v=20260213"></script>
<script src="/static/js/components/mobile-bottom-nav.js?v=20260213"></script>
<script src="/static/js/pages/issues-dashboard.js?v=20260213"></script>
<script src="/static/js/core/permissions.js?v=20260306"></script>
<script src="/static/js/components/common-header.js?v=20260306"></script>
<script src="/static/js/core/page-manager.js?v=20260306"></script>
<script src="/static/js/core/auth-manager.js?v=20260306"></script>
<script src="/static/js/utils/issue-helpers.js?v=20260306"></script>
<script src="/static/js/utils/photo-modal.js?v=20260306"></script>
<script src="/static/js/utils/toast.js?v=20260306"></script>
<script src="/static/js/components/mobile-bottom-nav.js?v=20260306"></script>
<script src="/static/js/api.js?v=20260306"></script>
<script src="/static/js/pages/issues-dashboard.js?v=20260306"></script>
</body>
</html>