This commit is contained in:
yabo0812
2025-10-21 14:21:00 +09:00
4 changed files with 605 additions and 4 deletions
+329 -1
View File
@@ -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
View File
@@ -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개 문서 선택
[맥락 기반 설명 생성]