feat: 완전한 웹 UI 구현 및 문서 처리 파이프라인 완성
✨ 새로운 기능: - FastAPI 기반 완전한 웹 UI 구현 - 반응형 디자인 (모바일/태블릿 지원) - 드래그앤드롭 파일 업로드 인터페이스 - 실시간 AI 챗봇 인터페이스 - 문서 관리 및 검색 시스템 - 진행률 표시 및 상태 알림 🎨 UI 구성: - 메인 대시보드: 서버 상태, 통계, 빠른 접근 - 파일 업로드: 드래그앤드롭, 처리 옵션, 진행률 - 문서 관리: 검색, 정렬, 미리보기, 다운로드 - AI 챗봇: 실시간 대화, 문서 기반 RAG, 빠른 질문 🔧 기술 스택: - FastAPI + Jinja2 템플릿 - 모던 CSS (그라디언트, 애니메이션) - Font Awesome 아이콘 - JavaScript (ES6+) 🚀 완성된 기능: - 파일 업로드 → 텍스트 추출 → 임베딩 → 번역 → HTML 생성 - 벡터 검색 및 RAG 기반 질의응답 - 다중 모델 지원 (기본/부스팅/영어 전용) - API 키 인증 및 CORS 설정 - NAS 연동 및 파일 내보내기
This commit is contained in:
229
templates/index.html
Normal file
229
templates/index.html
Normal file
@@ -0,0 +1,229 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}AI 문서 처리 서버 - 대시보드{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h1 class="card-title">
|
||||
<i class="fas fa-tachometer-alt"></i> 대시보드
|
||||
</h1>
|
||||
<p class="card-subtitle">AI 문서 처리 서버 현황을 확인하세요</p>
|
||||
</div>
|
||||
|
||||
<!-- 시스템 상태 -->
|
||||
<div class="grid grid-3">
|
||||
<div class="card">
|
||||
<h3><i class="fas fa-server"></i> 서버 상태</h3>
|
||||
<div class="status status-success">
|
||||
<i class="fas fa-check-circle"></i> 정상 운영
|
||||
</div>
|
||||
<p class="mt-2">
|
||||
<strong>모델:</strong> {{ status.base_model }}<br>
|
||||
<strong>임베딩:</strong> {{ status.embedding_model }}<br>
|
||||
<strong>인덱스:</strong> {{ status.index_loaded }}개 문서
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3><i class="fas fa-upload"></i> 빠른 업로드</h3>
|
||||
<div class="drop-zone-mini" onclick="window.location.href='/upload'">
|
||||
<i class="fas fa-cloud-upload-alt"></i>
|
||||
<p>파일을 업로드하려면 클릭하세요</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3><i class="fas fa-search"></i> 빠른 검색</h3>
|
||||
<form onsubmit="quickSearch(event)">
|
||||
<input type="text" class="form-control" placeholder="문서 내용 검색..." id="quickSearchInput">
|
||||
<button type="submit" class="btn btn-primary mt-2 w-100">
|
||||
<i class="fas fa-search"></i> 검색
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 최근 문서 -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">
|
||||
<i class="fas fa-file-alt"></i> 최근 처리된 문서
|
||||
</h2>
|
||||
<a href="/documents" class="btn btn-secondary">모든 문서 보기</a>
|
||||
</div>
|
||||
|
||||
{% if recent_documents %}
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>문서 ID</th>
|
||||
<th>처리 시간</th>
|
||||
<th>청크 수</th>
|
||||
<th>상태</th>
|
||||
<th>액션</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for doc in recent_documents %}
|
||||
<tr>
|
||||
<td>{{ doc.id }}</td>
|
||||
<td>{{ doc.created_at }}</td>
|
||||
<td>{{ doc.chunks }}</td>
|
||||
<td>
|
||||
<span class="status status-success">
|
||||
<i class="fas fa-check"></i> 완료
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/html/{{ doc.html_file }}" class="btn btn-sm btn-primary" target="_blank">
|
||||
<i class="fas fa-eye"></i> 보기
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-4">
|
||||
<i class="fas fa-inbox fa-3x text-muted mb-3"></i>
|
||||
<p class="text-muted">아직 처리된 문서가 없습니다.</p>
|
||||
<a href="/upload" class="btn btn-primary">첫 문서 업로드하기</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- 통계 -->
|
||||
<div class="grid grid-2">
|
||||
<div class="card">
|
||||
<h3><i class="fas fa-chart-bar"></i> 처리 통계</h3>
|
||||
<div class="stats">
|
||||
<div class="stat-item">
|
||||
<span class="stat-number">{{ stats.total_documents }}</span>
|
||||
<span class="stat-label">총 문서 수</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-number">{{ stats.total_chunks }}</span>
|
||||
<span class="stat-label">총 청크 수</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-number">{{ stats.today_processed }}</span>
|
||||
<span class="stat-label">오늘 처리</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3><i class="fas fa-robot"></i> AI 챗봇</h3>
|
||||
<p>문서 기반 질의응답을 시작하세요.</p>
|
||||
<div class="quick-chat">
|
||||
<input type="text" class="form-control mb-2" placeholder="질문을 입력하세요..." id="quickChatInput">
|
||||
<button onclick="quickChat()" class="btn btn-success w-100">
|
||||
<i class="fas fa-paper-plane"></i> 질문하기
|
||||
</button>
|
||||
</div>
|
||||
<a href="/chat" class="btn btn-secondary w-100 mt-2">전체 채팅 화면으로</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.drop-zone-mini {
|
||||
border: 2px dashed #ced4da;
|
||||
border-radius: 10px;
|
||||
padding: 2rem 1rem;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.drop-zone-mini:hover {
|
||||
border-color: #667eea;
|
||||
background-color: rgba(102, 126, 234, 0.05);
|
||||
}
|
||||
|
||||
.drop-zone-mini i {
|
||||
font-size: 2rem;
|
||||
color: #6c757d;
|
||||
margin-bottom: 0.5rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
padding: 1rem;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
display: block;
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.85rem;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.mt-2 { margin-top: 0.5rem; }
|
||||
.mb-2 { margin-bottom: 0.5rem; }
|
||||
.mb-3 { margin-bottom: 1rem; }
|
||||
.py-4 { padding: 2rem 0; }
|
||||
.w-100 { width: 100%; }
|
||||
.text-center { text-align: center; }
|
||||
.text-muted { color: #6c757d; }
|
||||
.table-responsive { overflow-x: auto; }
|
||||
.btn-sm { padding: 0.25rem 0.5rem; font-size: 0.875rem; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
function quickSearch(event) {
|
||||
event.preventDefault();
|
||||
const query = document.getElementById('quickSearchInput').value;
|
||||
if (query.trim()) {
|
||||
window.location.href = `/search?q=${encodeURIComponent(query)}`;
|
||||
}
|
||||
}
|
||||
|
||||
function quickChat() {
|
||||
const question = document.getElementById('quickChatInput').value;
|
||||
if (question.trim()) {
|
||||
// 간단한 챗봇 미리보기 (실제 구현은 /chat 페이지에서)
|
||||
alert('채팅 기능은 "AI 챗봇" 페이지에서 이용하실 수 있습니다.');
|
||||
window.location.href = '/chat';
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 로드 시 서버 상태 업데이트
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 실시간 상태 업데이트 (선택사항)
|
||||
updateStatus();
|
||||
});
|
||||
|
||||
async function updateStatus() {
|
||||
try {
|
||||
const response = await fetch('/health');
|
||||
const data = await response.json();
|
||||
// 상태 업데이트 로직
|
||||
console.log('서버 상태:', data);
|
||||
} catch (error) {
|
||||
console.error('상태 확인 실패:', error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user