mirror of
https://github.com/hwanny1128/HGZero.git
synced 2026-06-13 01:19:11 +00:00
Merge branch 'main' of https://github.com/hwanny1128/HGZero
This commit is contained in:
@@ -135,6 +135,195 @@
|
||||
background: var(--gray-50);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* UFR-AI-040: 관련 회의록 자동 연결 스타일 */
|
||||
.related-meetings-section {
|
||||
background: linear-gradient(135deg, var(--accent-50) 0%, var(--primary-50) 100%);
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid var(--accent-200);
|
||||
}
|
||||
|
||||
.related-meetings-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
margin-bottom: 0;
|
||||
transition: all var(--transition-normal);
|
||||
}
|
||||
|
||||
.related-meetings-header:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.related-meetings-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.related-meetings-title h3 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--gray-900);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ai-badge-small {
|
||||
background: var(--accent-500);
|
||||
color: var(--white);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
padding: 3px 8px;
|
||||
border-radius: 12px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.chevron-icon {
|
||||
transition: transform 0.3s ease;
|
||||
color: var(--gray-600);
|
||||
}
|
||||
|
||||
.chevron-icon.expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.related-meetings-content {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease-in-out;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.related-meetings-content.expanded {
|
||||
max-height: 800px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.related-meeting-card {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--gray-200);
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-normal);
|
||||
}
|
||||
|
||||
.related-meeting-card:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.related-meeting-card:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-2px);
|
||||
border-color: var(--primary-500);
|
||||
}
|
||||
|
||||
.related-meeting-card:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.meeting-card-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.meeting-card-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--gray-900);
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.relevance-score {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
padding: 4px 8px;
|
||||
border-radius: 12px;
|
||||
white-space: nowrap;
|
||||
margin-left: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.relevance-high {
|
||||
background-color: var(--success-bg);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.relevance-medium {
|
||||
background-color: var(--primary-50);
|
||||
color: var(--primary-500);
|
||||
}
|
||||
|
||||
.relevance-low {
|
||||
background-color: var(--gray-100);
|
||||
color: var(--gray-700);
|
||||
}
|
||||
|
||||
.meeting-card-meta {
|
||||
font-size: 12px;
|
||||
color: var(--gray-600);
|
||||
margin-bottom: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.meeting-card-attendees {
|
||||
font-size: 12px;
|
||||
color: var(--gray-700);
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.meeting-card-keywords {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.keyword-tag {
|
||||
background-color: var(--accent-100);
|
||||
color: var(--accent-700);
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.meeting-card-summary {
|
||||
font-size: 12px;
|
||||
color: var(--gray-600);
|
||||
margin-top: 8px;
|
||||
line-height: 1.4;
|
||||
border-top: 1px solid var(--gray-100);
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.no-related-meetings {
|
||||
text-align: center;
|
||||
padding: 24px;
|
||||
color: var(--gray-500);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.no-related-meetings .material-symbols-outlined {
|
||||
font-size: 48px;
|
||||
opacity: 0.3;
|
||||
margin-bottom: 8px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -173,6 +362,22 @@
|
||||
<span>AI가 발언 내용을 분석하여 회의록을 작성하고 있습니다</span>
|
||||
</div>
|
||||
|
||||
<!-- UFR-AI-040: 관련 회의록 자동 연결 섹션 -->
|
||||
<div class="related-meetings-section">
|
||||
<div class="related-meetings-header" onclick="toggleRelatedMeetings()">
|
||||
<div class="related-meetings-title">
|
||||
<span class="ai-badge-small">AI</span>
|
||||
<h3>관련 회의록 <span style="color: var(--gray-600); font-weight: normal;" id="relatedCount">(분석 중...)</span></h3>
|
||||
</div>
|
||||
<span class="material-symbols-outlined chevron-icon" id="chevronIcon">expand_more</span>
|
||||
</div>
|
||||
<div class="related-meetings-content" id="relatedMeetingsContent">
|
||||
<div id="relatedMeetingsList">
|
||||
<!-- JavaScript로 동적 생성 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 회의록 섹션들 -->
|
||||
<div id="sectionList">
|
||||
<!-- JavaScript로 동적 생성 -->
|
||||
@@ -213,7 +418,41 @@
|
||||
let startTime = Date.now();
|
||||
let elapsedInterval;
|
||||
|
||||
// 프롬프트 유형 정의 (NEW - UFR-AI-030)
|
||||
// UFR-AI-040: 관련 회의록 데이터 (AI가 자동으로 찾아서 연결)
|
||||
const RELATED_MEETINGS = [
|
||||
{
|
||||
id: 'MTG-2025-001',
|
||||
title: '프로젝트 초기 기획 회의',
|
||||
date: '2025-10-15',
|
||||
attendees: ['김철수', '이영희', '박민수'],
|
||||
relevanceScore: 87,
|
||||
keywords: ['프로젝트', 'Mobile First', '기획', '킥오프'],
|
||||
summary: '프로젝트 초기 방향성 논의 및 Mobile First 전략 수립. 개발 기간과 주요 마일스톤 확정.',
|
||||
folder: '프로젝트/회의록'
|
||||
},
|
||||
{
|
||||
id: 'MTG-2025-002',
|
||||
title: '마이크로서비스 아키텍처 설계 회의',
|
||||
date: '2025-10-18',
|
||||
attendees: ['김철수', '정도현', '이영희'],
|
||||
relevanceScore: 78,
|
||||
keywords: ['마이크로서비스', '아키텍처', 'API', '설계'],
|
||||
summary: '서비스 분리 기준 및 API 설계 방향 논의. 데이터베이스 구조와 통신 프로토콜 결정.',
|
||||
folder: '프로젝트/회의록'
|
||||
},
|
||||
{
|
||||
id: 'MTG-2025-003',
|
||||
title: 'UI/UX 디자인 리뷰 회의',
|
||||
date: '2025-10-19',
|
||||
attendees: ['이영희', '최유진', '박민수'],
|
||||
relevanceScore: 72,
|
||||
keywords: ['UI/UX', 'Mobile', '디자인', '사용자경험'],
|
||||
summary: 'Mobile First 디자인 시스템 및 사용자 경험 개선 방안. 프로토타입 피드백 반영.',
|
||||
folder: '프로젝트/회의록'
|
||||
}
|
||||
];
|
||||
|
||||
// 프롬프트 유형 정의 (UFR-AI-030)
|
||||
const PROMPT_TYPES = {
|
||||
onePage: {
|
||||
id: 'onePage',
|
||||
@@ -288,6 +527,92 @@
|
||||
|
||||
elapsedInterval = setInterval(updateElapsedTime, 1000);
|
||||
|
||||
// UFR-AI-040: 관련 회의록 토글
|
||||
function toggleRelatedMeetings() {
|
||||
const content = document.getElementById('relatedMeetingsContent');
|
||||
const chevron = document.getElementById('chevronIcon');
|
||||
|
||||
content.classList.toggle('expanded');
|
||||
chevron.classList.toggle('expanded');
|
||||
|
||||
// 처음 열 때만 렌더링
|
||||
if (content.classList.contains('expanded') && !content.dataset.rendered) {
|
||||
renderRelatedMeetings();
|
||||
content.dataset.rendered = 'true';
|
||||
}
|
||||
}
|
||||
|
||||
// UFR-AI-040: 관련 회의록 렌더링
|
||||
function renderRelatedMeetings() {
|
||||
const container = document.getElementById('relatedMeetingsList');
|
||||
|
||||
if (RELATED_MEETINGS.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="no-related-meetings">
|
||||
<span class="material-symbols-outlined">search_off</span>
|
||||
<p>관련된 회의록을 찾을 수 없습니다</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = RELATED_MEETINGS.map(meeting => {
|
||||
const scoreClass = getRelevanceClass(meeting.relevanceScore);
|
||||
const scoreLabel = meeting.relevanceScore + '%';
|
||||
|
||||
return `
|
||||
<div class="related-meeting-card" onclick="navigateToRelatedMeeting('${meeting.id}')">
|
||||
<div class="meeting-card-header">
|
||||
<h4 class="meeting-card-title">${meeting.title}</h4>
|
||||
<span class="relevance-score ${scoreClass}">${scoreLabel}</span>
|
||||
</div>
|
||||
<div class="meeting-card-meta">
|
||||
<span class="material-symbols-outlined" style="font-size: 14px;">calendar_today</span>
|
||||
${meeting.date}
|
||||
</div>
|
||||
<div class="meeting-card-attendees">
|
||||
<span class="material-symbols-outlined" style="font-size: 14px;">group</span>
|
||||
${meeting.attendees.join(', ')}
|
||||
</div>
|
||||
<div class="meeting-card-keywords">
|
||||
${meeting.keywords.map(keyword =>
|
||||
`<span class="keyword-tag">${keyword}</span>`
|
||||
).join('')}
|
||||
</div>
|
||||
<div class="meeting-card-summary">
|
||||
${meeting.summary}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
// 관련 회의록 개수 업데이트
|
||||
document.getElementById('relatedCount').textContent = `(${RELATED_MEETINGS.length}건)`;
|
||||
}
|
||||
|
||||
// UFR-AI-040: 유사도 점수에 따른 색상 클래스 반환
|
||||
function getRelevanceClass(score) {
|
||||
if (score >= 85) return 'relevance-high'; // 85-100%: 녹색 (높은 관련성)
|
||||
if (score >= 75) return 'relevance-medium'; // 75-84%: 파란색 (중간 관련성)
|
||||
return 'relevance-low'; // 70-74%: 회색 (낮은 관련성)
|
||||
}
|
||||
|
||||
// UFR-AI-040: 관련 회의록으로 이동
|
||||
function navigateToRelatedMeeting(meetingId) {
|
||||
UIComponents.showToast(`회의록 상세 화면으로 이동: ${meetingId}`, 'info');
|
||||
// TODO: 실제로는 회의록 상세 화면(10-회의록상세조회.html)으로 이동
|
||||
// NavigationHelper.navigate('MEETING_DETAIL', { meetingId });
|
||||
}
|
||||
|
||||
// UFR-AI-040: 관련 회의록 AI 분석 시뮬레이션
|
||||
function simulateRelatedMeetingsAnalysis() {
|
||||
// 2초 후 관련 회의록 개수 표시
|
||||
setTimeout(() => {
|
||||
document.getElementById('relatedCount').textContent = `(${RELATED_MEETINGS.length}건)`;
|
||||
UIComponents.showToast(`AI가 ${RELATED_MEETINGS.length}건의 관련 회의록을 찾았습니다`, 'success', 3000);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
// 섹션 렌더링
|
||||
function renderSections() {
|
||||
const container = document.getElementById('sectionList');
|
||||
@@ -648,6 +973,9 @@
|
||||
// 초기 렌더링
|
||||
renderSections();
|
||||
|
||||
// UFR-AI-040: 관련 회의록 AI 분석 시작
|
||||
simulateRelatedMeetingsAnalysis();
|
||||
|
||||
// 실시간 발언 시뮬레이션
|
||||
const speeches = [
|
||||
{ speaker: '김철수', text: '프로젝트 킥오프 회의를 시작하겠습니다...' },
|
||||
|
||||
+3
-3
@@ -30,7 +30,7 @@
|
||||
2. **Meeting** - 회의 관리, 회의록 생성 및 관리, 회의록 공유
|
||||
3. **STT** - 음성 녹음 관리, 음성-텍스트 변환, 화자 식별 (기본 기능)
|
||||
4. **AI** - LLM 기반 회의록 자동 작성, Todo 자동 추출, 프롬프팅 기반 회의록 개선
|
||||
5. **RAG** - 맥락 기반 용어 설명, 관련 문서 검색 및 연결, 업무 이력 통합
|
||||
5. **RAG** - 맥락 기반 용어 설명, 관련된 이전 회의록 검색 및 연결, 업무 이력 통합
|
||||
6. **Collaboration** - 실시간 동기화, 버전 관리, 충돌 해결
|
||||
7. **Todo** - Todo 할당 및 관리, 진행 상황 추적, 회의록 실시간 연동
|
||||
|
||||
@@ -518,14 +518,14 @@ UFR-RAG-010: [전문용어감지] 회의록 작성자로서 | 나는, 업무 지
|
||||
|
||||
UFR-RAG-020: [맥락기반용어설명] 회의록 작성자로서 | 나는, 전문용어를 맥락에 맞게 이해하기 위해 | 관련 회의록과 업무 이력을 바탕으로 실용적인 설명을 제공받고 싶다.
|
||||
- 시나리오: 맥락 기반 용어 설명 자동 제공
|
||||
전문용어가 감지된 상황에서 | RAG 시스템이 관련 문서를 검색하면 | 과거 회의록 및 업무 이력에서 맥락에 맞는 실용적인 설명이 생성되어 제공된다.
|
||||
전문용어가 감지된 상황에서 | RAG 시스템이 관련 이전 회의록를 검색하면 | 과거 회의록 및 업무 이력에서 맥락에 맞는 실용적인 설명이 생성되어 제공된다.
|
||||
|
||||
[RAG 검색 수행]
|
||||
- 벡터 유사도 검색
|
||||
- 과거 회의록 검색 (동일 용어 사용 사례)
|
||||
- 사내 문서 저장소 검색 (위키, 매뉴얼, 보고서)
|
||||
- 업무 이력 검색 (프로젝트 문서, 이메일 등)
|
||||
- 관련 문서 추출 (관련도 점수순)
|
||||
- 관련 이전 회의록 추출 (관련도 점수순)
|
||||
- 최대 5개 문서 선택
|
||||
|
||||
[맥락 기반 설명 생성]
|
||||
|
||||
Reference in New Issue
Block a user