jeongsoo's picture
Initial commit
5ccf0d4
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ν•œκ΅­μ–΄ 단어 의미 λ„€νŠΈμ›Œν¬ μ‹œκ°ν™”</title>
<!-- Plotly.js -->
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
font-family: 'Malgun Gothic', 'Apple Gothic', 'NanumGothic', sans-serif;
padding: 20px;
background-color: #f8f9fa;
}
#graphContainer {
height: 80vh;
width: 100%;
border-radius: 8px;
background-color: #fff;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
.controls-container {
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
.spinner {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1000;
}
.info-section {
margin-top: 20px;
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
h1, h3 {
color: #343a40;
}
.btn-primary {
background-color: #5a67d8;
border-color: #5a67d8;
}
.btn-primary:hover {
background-color: #4c51bf;
border-color: #4c51bf;
}
</style>
</head>
<body>
<div class="container">
<div class="row mb-4">
<div class="col-12">
<h1 class="text-center my-4">ν•œκ΅­μ–΄ 단어 의미 λ„€νŠΈμ›Œν¬ μ‹œκ°ν™”</h1>
<div class="alert alert-info" role="alert">
이 λ„κ΅¬λŠ” ν•œκ΅­μ–΄ 단어듀 κ°„μ˜ 의미적 관계λ₯Ό 3D κ³΅κ°„μ—μ„œ μ‹œκ°ν™”ν•©λ‹ˆλ‹€. BGE-M3 λ‹€κ΅­μ–΄ μž„λ² λ”© λͺ¨λΈμ„ μ‚¬μš©ν•˜μ—¬ 단어 κ°„ 의미적 μœ μ‚¬μ„±μ„ λΆ„μ„ν•©λ‹ˆλ‹€.
</div>
</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="controls-container">
<h3>μ„€μ •</h3>
<div class="mb-3">
<label for="thresholdSlider" class="form-label">μœ μ‚¬λ„ μž„κ³„κ°’ ({{ threshold }})</label>
<input type="range" class="form-range" id="thresholdSlider" min="0.1" max="0.9" step="0.05" v-model="threshold">
<div class="form-text">높은 κ°’ = 더 μ—„κ²©ν•œ μ—°κ²° κΈ°μ€€ (적은 μ—£μ§€)</div>
</div>
<div class="d-grid gap-2">
<button class="btn btn-primary" @click="generateGraph" :disabled="isLoading">
κ·Έλž˜ν”„ 생성
</button>
</div>
<div class="info-section">
<h3>데이터 정보</h3>
<div v-if="dataInfo">
<p><strong>단어 수:</strong> {{ dataInfo.wordCount }}</p>
<p><strong>μƒ˜ν”Œ 단어:</strong></p>
<div class="text-muted">{{ dataInfo.sampleWords.join(', ') }}</div>
</div>
<div v-else>
<p class="text-muted">데이터 정보λ₯Ό λ‘œλ“œ μ€‘μž…λ‹ˆλ‹€...</p>
</div>
</div>
</div>
</div>
<div class="col-md-9">
<div id="graphContainer" style="position: relative;">
<div class="spinner" v-if="isLoading">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">λ‘œλ”© 쀑...</span>
</div>
</div>
</div>
<div class="alert alert-secondary">
<h5>μ‘°μž‘ 방법:</h5>
<ul>
<li>마우슀 휠: ν™•λŒ€/μΆ•μ†Œ</li>
<li>마우슀 λ“œλž˜κ·Έ: νšŒμ „</li>
<li>마우슀 였λ₯Έμͺ½ λ²„νŠΌ λ“œλž˜κ·Έ: 이동</li>
<li>단어에 마우슀 μ˜€λ²„: 상세 정보 확인</li>
</ul>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-12">
<div class="card">
<div class="card-body">
<h3 class="card-title">이 μ‹œκ°ν™”μ— λŒ€ν•΄</h3>
<p class="card-text">
이 λ„κ΅¬λŠ” λ‹€μŒκ³Ό 같은 κΈ°μˆ μ„ μ‚¬μš©ν•˜μ—¬ ν•œκ΅­μ–΄ 단어 λ„€νŠΈμ›Œν¬λ₯Ό μ‹œκ°ν™”ν•©λ‹ˆλ‹€:
</p>
<ul>
<li><strong>BAAI/bge-m3 μž„λ² λ”©:</strong> λ‹€μ–‘ν•œ 언어에 μ΅œμ ν™”λœ μ΅œμ‹  μž„λ² λ”© λͺ¨λΈλ‘œ, ν•œκ΅­μ–΄μ—μ„œλ„ μš°μˆ˜ν•œ μ„±λŠ₯을 λ³΄μž…λ‹ˆλ‹€.</li>
<li><strong>t-SNE 차원 μΆ•μ†Œ:</strong> λ³΅μž‘ν•œ 고차원 벑터λ₯Ό 3D 곡간에 νˆ¬μ˜ν•˜μ—¬ 의미적 관계λ₯Ό μ‹œκ°ν™”ν•©λ‹ˆλ‹€.</li>
<li><strong>코사인 μœ μ‚¬λ„:</strong> 단어 벑터 κ°„ 각도λ₯Ό 기반으둜 의미적 μœ μ‚¬μ„±μ„ μΈ‘μ •ν•©λ‹ˆλ‹€.</li>
<li><strong>Plotly μ‹œκ°ν™”:</strong> μΈν„°λž™ν‹°λΈŒν•œ 3D μ‹œκ°ν™”λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.</li>
</ul>
<p class="card-text">
각 λ‹¨μ–΄λŠ” 3D κ³΅κ°„μ˜ 점으둜 ν‘œμ‹œλ˜λ©°, μœ μ‚¬λ„κ°€ 높은 단어듀은 μ—°κ²°μ„ (μ—£μ§€)으둜 μ—°κ²°λ©λ‹ˆλ‹€. 색상은 zμΆ• 값에 따라 λ‹€λ₯΄κ²Œ ν‘œμ‹œλ©λ‹ˆλ‹€.
</p>
</div>
</div>
</div>
</div>
</div>
<!-- Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.36/dist/vue.global.prod.js"></script>
<!-- Axios -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
const app = Vue.createApp({
data() {
return {
threshold: 0.7,
isLoading: false,
dataInfo: null,
errorMessage: ''
}
},
mounted() {
this.loadDataInfo();
this.generateGraph();
},
methods: {
loadDataInfo() {
axios.get('/data-info')
.then(response => {
this.dataInfo = response.data;
})
.catch(error => {
console.error('데이터 정보 λ‘œλ“œ 였λ₯˜:', error);
});
},
generateGraph() {
this.isLoading = true;
this.errorMessage = '';
axios.post('/generate-graph', {
threshold: this.threshold,
use_default_data: true
})
.then(response => {
const graphData = response.data;
Plotly.newPlot('graphContainer', JSON.parse(graphData));
this.isLoading = false;
})
.catch(error => {
console.error('κ·Έλž˜ν”„ 생성 였λ₯˜:', error);
this.errorMessage = 'κ·Έλž˜ν”„ 생성 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.';
this.isLoading = false;
});
}
}
});
app.mount('.container');
</script>
</body>
</html>