feat: add interactive demos for AI history, Auth design, and Git intro
This commit is contained in:
@@ -0,0 +1,305 @@
|
||||
<template>
|
||||
<div class="ai-evolution-timeline-demo">
|
||||
<div class="timeline-container">
|
||||
<div class="timeline-track"></div>
|
||||
|
||||
<div
|
||||
v-for="(era, index) in eras"
|
||||
:key="index"
|
||||
class="timeline-era"
|
||||
:class="{ active: activeEra === index }"
|
||||
@click="activeEra = index"
|
||||
>
|
||||
<div class="era-marker">
|
||||
<div class="marker-dot"></div>
|
||||
<div class="marker-line"></div>
|
||||
</div>
|
||||
<div class="era-content">
|
||||
<div class="era-year">{{ era.year }}</div>
|
||||
<div class="era-title">{{ era.title }}</div>
|
||||
<div class="era-desc">{{ era.desc }}</div>
|
||||
<div class="era-examples">
|
||||
<span
|
||||
v-for="(example, i) in era.examples"
|
||||
:key="i"
|
||||
class="example-tag"
|
||||
>
|
||||
{{ example }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Era Details Panel -->
|
||||
<transition name="fade">
|
||||
<div v-if="activeEra !== null" class="era-details">
|
||||
<div class="details-header">
|
||||
<h4>{{ eras[activeEra].title }}</h4>
|
||||
<span class="year-badge">{{ eras[activeEra].year }}</span>
|
||||
</div>
|
||||
<div class="details-content">
|
||||
<p>{{ eras[activeEra].fullDesc }}</p>
|
||||
<div class="key-points">
|
||||
<h5>核心特点:</h5>
|
||||
<ul>
|
||||
<li v-for="(point, i) in eras[activeEra].keyPoints" :key="i">
|
||||
{{ point }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const activeEra = ref(0)
|
||||
|
||||
const eras = ref([
|
||||
{
|
||||
year: '20世纪50-80年代',
|
||||
title: '符号主义时代',
|
||||
desc: '规则与逻辑推理',
|
||||
fullDesc: '早期人工智能研究认为,智能可以通过符号和逻辑规则来表达。科学家们尝试编写大量规则来让机器模拟人类专家的决策过程。',
|
||||
examples: ['专家系统', '深蓝', 'MYCIN'],
|
||||
keyPoints: [
|
||||
'人工编写 If-Then 规则',
|
||||
'逻辑推理能力强大',
|
||||
'可解释性强',
|
||||
'无法处理复杂现实世界',
|
||||
'容易遇到组合爆炸问题'
|
||||
]
|
||||
},
|
||||
{
|
||||
year: '21世纪10年代',
|
||||
title: '连接主义时代',
|
||||
desc: '神经网络与深度学习',
|
||||
fullDesc: '随着大数据和 GPU 算力的突破,深度学习迎来了春天。神经网络通过多层结构自动学习特征,在图像识别、语音识别等领域取得巨大成功。',
|
||||
examples: ['AlexNet', 'AlphaGo', '人脸识别'],
|
||||
keyPoints: [
|
||||
'模仿人脑神经元结构',
|
||||
'从数据中自动学习',
|
||||
'强大的模式识别能力',
|
||||
'需要海量标注数据',
|
||||
'黑盒模型,缺乏可解释性'
|
||||
]
|
||||
},
|
||||
{
|
||||
year: '21世纪20年代至今',
|
||||
title: '生成式人工智能时代',
|
||||
desc: '大模型与创造力',
|
||||
fullDesc: 'Transformer 架构的诞生让机器理解了上下文关系。GPT 等大语言模型不仅能生成文本、图像,还展现出了惊人的推理和创造能力。',
|
||||
examples: ['ChatGPT', 'Midjourney', 'GPT-4'],
|
||||
keyPoints: [
|
||||
'基于注意力机制',
|
||||
'理解上下文和语义',
|
||||
'能生成新内容',
|
||||
'通用智能雏形',
|
||||
'存在幻觉和偏见问题'
|
||||
]
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ai-evolution-timeline-demo {
|
||||
margin: 1rem 0;
|
||||
padding: 1.5rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.timeline-container {
|
||||
position: relative;
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.timeline-track {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 4px;
|
||||
background: var(--vp-c-divider);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.timeline-era {
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin-bottom: 2rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.timeline-era:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.timeline-era.active .era-marker .marker-dot {
|
||||
background: var(--vp-c-brand);
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.era-marker {
|
||||
position: relative;
|
||||
width: 44px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.marker-dot {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 50%;
|
||||
border: 3px solid var(--vp-c-divider);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.marker-line {
|
||||
flex: 1;
|
||||
width: 2px;
|
||||
background: var(--vp-c-divider);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.timeline-era:last-child .marker-line {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.era-content {
|
||||
margin-left: 1rem;
|
||||
padding: 1rem 1.5rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
transition: all 0.3s ease;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.timeline-era.active .era-content {
|
||||
border-color: var(--vp-c-brand);
|
||||
box-shadow: 0 0 0 3px rgba(var(--vp-c-brand-rgb), 0.12);
|
||||
}
|
||||
|
||||
.era-year {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.era-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.25rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.era-desc {
|
||||
font-size: 0.875rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.era-examples {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.example-tag {
|
||||
padding: 0.25rem 0.75rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 20px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.era-details {
|
||||
margin-top: 1.5rem;
|
||||
padding: 1.5rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.details-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.details-header h4 {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.year-badge {
|
||||
padding: 0.5rem 1rem;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.12);
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.2);
|
||||
color: var(--vp-c-brand);
|
||||
border-radius: 20px;
|
||||
font-weight: 600;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.details-content p {
|
||||
line-height: 1.8;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.key-points {
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem 1.5rem;
|
||||
border-radius: 6px;
|
||||
border-left: 4px solid var(--vp-c-brand);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.key-points h5 {
|
||||
margin: 0 0 0.75rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.key-points ul {
|
||||
margin: 0;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
|
||||
.key-points li {
|
||||
margin-bottom: 0.5rem;
|
||||
line-height: 1.6;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -197,21 +197,17 @@ const stages = [
|
||||
|
||||
<style scoped>
|
||||
.ai-evolution-demo {
|
||||
border-radius: 16px;
|
||||
background: var(--vp-c-bg);
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
overflow: hidden;
|
||||
margin: 2rem 0;
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial,
|
||||
sans-serif;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
/* Reusing Timeline Styles from FrontendEvolutionDemo for consistency */
|
||||
.timeline-container {
|
||||
padding: 2rem 1rem 1rem;
|
||||
background: linear-gradient(to bottom, var(--vp-c-bg-soft), var(--vp-c-bg));
|
||||
background: var(--vp-c-bg-soft);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
@@ -325,13 +321,7 @@ const stages = [
|
||||
.header-section h3 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
background: linear-gradient(
|
||||
120deg,
|
||||
#10b981,
|
||||
#3b82f6
|
||||
); /* Green to Blue for AI */
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.stage-index {
|
||||
@@ -362,29 +352,24 @@ const stages = [
|
||||
|
||||
.mac-window {
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: white;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
.mac-window:hover {
|
||||
transform: translateY(-5px);
|
||||
background: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.concept-window {
|
||||
background: #f8fafc;
|
||||
background: var(--vp-c-bg);
|
||||
}
|
||||
.app-window {
|
||||
background: white;
|
||||
background: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.window-bar {
|
||||
padding: 0.8rem 1rem;
|
||||
background: white;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
@@ -400,13 +385,13 @@ const stages = [
|
||||
border-radius: 50%;
|
||||
}
|
||||
.light.red {
|
||||
background: #ff5f56;
|
||||
background: var(--vp-c-red-1, #ef4444);
|
||||
}
|
||||
.light.yellow {
|
||||
background: #ffbd2e;
|
||||
background: var(--vp-c-yellow-1, #f59e0b);
|
||||
}
|
||||
.light.green {
|
||||
background: #27c93f;
|
||||
background: var(--vp-c-green-1, #22c55e);
|
||||
}
|
||||
|
||||
.window-title {
|
||||
@@ -432,30 +417,30 @@ const stages = [
|
||||
/* Visualizations */
|
||||
/* Symbolism */
|
||||
.logic-gate {
|
||||
border: 2px solid #334155;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
background: white;
|
||||
background: var(--vp-c-bg);
|
||||
}
|
||||
.input-group {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
margin-bottom: 0.5rem;
|
||||
font-family: monospace;
|
||||
font-family: var(--vp-font-family-mono);
|
||||
}
|
||||
.gate-box {
|
||||
background: #334155;
|
||||
color: white;
|
||||
background: var(--vp-c-brand);
|
||||
color: var(--vp-c-bg);
|
||||
padding: 4px 10px;
|
||||
margin: 0.5rem 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.math-note {
|
||||
margin-top: 1rem;
|
||||
font-family: monospace;
|
||||
color: #64748b;
|
||||
font-family: var(--vp-font-family-mono);
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
@@ -467,15 +452,16 @@ const stages = [
|
||||
gap: 1rem;
|
||||
}
|
||||
.tree-node {
|
||||
border: 1px solid #cbd5e1;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
padding: 6px 12px;
|
||||
border-radius: 20px;
|
||||
background: white;
|
||||
background: var(--vp-c-bg);
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
.tree-node.root {
|
||||
border-color: #3b82f6;
|
||||
color: #3b82f6;
|
||||
border-color: var(--vp-c-brand);
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: bold;
|
||||
}
|
||||
.branches {
|
||||
@@ -490,15 +476,15 @@ const stages = [
|
||||
}
|
||||
.condition {
|
||||
font-size: 0.7rem;
|
||||
color: #64748b;
|
||||
background: #f1f5f9;
|
||||
color: var(--vp-c-text-2);
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.kb-note {
|
||||
margin-top: 1rem;
|
||||
font-size: 0.8rem;
|
||||
color: #64748b;
|
||||
color: var(--vp-c-text-2);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@@ -518,17 +504,17 @@ const stages = [
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: #cbd5e1;
|
||||
border: 1px solid #94a3b8;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
.layer.input .neuron {
|
||||
background: #93c5fd;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.25);
|
||||
}
|
||||
.layer.hidden .neuron {
|
||||
background: #fca5a5;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.18);
|
||||
}
|
||||
.layer.output .neuron {
|
||||
background: #86efac;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.12);
|
||||
}
|
||||
.connections {
|
||||
position: absolute;
|
||||
@@ -540,13 +526,13 @@ const stages = [
|
||||
opacity: 0.2;
|
||||
}
|
||||
.connections line {
|
||||
stroke: #000;
|
||||
stroke: var(--vp-c-text-2);
|
||||
stroke-width: 1;
|
||||
}
|
||||
.dl-note {
|
||||
margin-top: 2rem;
|
||||
font-size: 0.8rem;
|
||||
color: #64748b;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
/* GenAI */
|
||||
@@ -558,16 +544,16 @@ const stages = [
|
||||
width: 100%;
|
||||
}
|
||||
.transformer-block {
|
||||
border: 2px solid #8b5cf6;
|
||||
border: 2px solid var(--vp-c-brand);
|
||||
border-radius: 8px;
|
||||
padding: 0.5rem;
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
background: #f5f3ff;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.08);
|
||||
}
|
||||
.block-layer {
|
||||
border: 1px solid #ddd6fe;
|
||||
background: white;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg);
|
||||
margin: 4px 0;
|
||||
padding: 4px;
|
||||
font-size: 0.7rem;
|
||||
@@ -575,10 +561,10 @@ const stages = [
|
||||
}
|
||||
.chat-sim {
|
||||
width: 100%;
|
||||
border: 1px solid #e2e8f0;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
background: white;
|
||||
background: var(--vp-c-bg);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.msg {
|
||||
@@ -588,14 +574,14 @@ const stages = [
|
||||
max-width: 80%;
|
||||
}
|
||||
.msg.user {
|
||||
background: #eff6ff;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.1);
|
||||
margin-left: auto;
|
||||
color: #1e40af;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
.msg.ai {
|
||||
background: #f0fdf4;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin-right: auto;
|
||||
color: #166534;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
/* Impact Card */
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
<template>
|
||||
<div class="attention-mechanism-demo">
|
||||
<div class="demo-header">
|
||||
<h4>👁️ 注意力机制演示</h4>
|
||||
<p>点击词语,观察它如何"关注"句子中的其他词</p>
|
||||
</div>
|
||||
|
||||
<div class="sentence-container">
|
||||
<div class="sentence">
|
||||
<span
|
||||
v-for="(word, index) in sentence"
|
||||
:key="index"
|
||||
:class="['word-token', { active: activeIndex === index, source: activeIndex === index }]"
|
||||
@click="selectWord(index)"
|
||||
>
|
||||
{{ word }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="attention-heatmap">
|
||||
<transition-group name="fade">
|
||||
<div
|
||||
v-for="(attention, index) in attentionWeights"
|
||||
:key="index"
|
||||
v-show="activeIndex !== null"
|
||||
:class="['attention-bar', { highlight: attention.weight > 0.5 }]"
|
||||
:style="{ width: (attention.weight * 100) + '%', opacity: activeIndex !== null ? 1 : 0 }"
|
||||
>
|
||||
<span class="attention-label">{{ attention.word }}: {{ (attention.weight * 100).toFixed(0) }}%</span>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="explanation-panel">
|
||||
<div v-if="activeIndex !== null" class="explanation-content">
|
||||
<h5>当前词: "{{ sentence[activeIndex] }}"</h5>
|
||||
<p><strong>注意力权重:</strong></p>
|
||||
<ul>
|
||||
<li v-for="(item, index) in attentionWeights" :key="index">
|
||||
"{{ item.word }}" - {{ (item.weight * 100).toFixed(0) }}% 的关注度
|
||||
</li>
|
||||
</ul>
|
||||
<p class="insight">
|
||||
💡 <strong>关键洞察:</strong> {{ getInsight(activeIndex) }}
|
||||
</p>
|
||||
</div>
|
||||
<div v-else class="placeholder">
|
||||
👆 点击句子中的任意词语开始
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const sentence = ref(['小明', '把', '苹果', '给了', '他', '的', '母亲'])
|
||||
const activeIndex = ref(null)
|
||||
|
||||
// 注意力权重矩阵(模拟)
|
||||
const attentionMatrix = {
|
||||
0: [0.15, 0.05, 0.60, 0.05, 0.05, 0.05, 0.05], // 小明 主要关注 苹果、他
|
||||
1: [0.10, 0.10, 0.40, 0.30, 0.05, 0.03, 0.02], // 把 主要关注 苹果、给了
|
||||
2: [0.50, 0.10, 0.15, 0.15, 0.05, 0.03, 0.02], // 苹果 主要关注 小明
|
||||
3: [0.10, 0.10, 0.35, 0.15, 0.20, 0.05, 0.05], // 给了 主要关注 苹果、他
|
||||
4: [0.65, 0.05, 0.10, 0.10, 0.05, 0.03, 0.02], // 他 主要关注 小明
|
||||
5: [0.08, 0.05, 0.07, 0.08, 0.62, 0.05, 0.05], // 的 主要关注 他
|
||||
6: [0.25, 0.10, 0.15, 0.15, 0.20, 0.10, 0.05] // 母亲 关注多个词
|
||||
}
|
||||
|
||||
const insights = {
|
||||
0: '当模型处理"小明"时,它最关注"苹果"(60%),因为这表明是"谁"拥有苹果。',
|
||||
1: '"把"是介词,模型关注"苹果"和"给了",理解动作的对象和方向。',
|
||||
2: '"苹果"作为宾语,主要关注主语"小明",确定归属关系。',
|
||||
3: '"给了"关注"苹果"和"他",理解传递动作的对象。',
|
||||
4: '"他"最关注"小明"(65%),因为"他"指代的就是"小明"!',
|
||||
5: '"的"连接"他"和"母亲",主要关注"他"(62%)。',
|
||||
6: '"母亲"作为句末宾语,关注前面的多个词语来理解完整语境。'
|
||||
}
|
||||
|
||||
const attentionWeights = computed(() => {
|
||||
if (activeIndex.value === null) return []
|
||||
|
||||
return sentence.value.map((word, index) => ({
|
||||
word,
|
||||
weight: attentionMatrix[activeIndex.value][index]
|
||||
}))
|
||||
})
|
||||
|
||||
const selectWord = (index) => {
|
||||
activeIndex.value = index
|
||||
}
|
||||
|
||||
const getInsight = (index) => {
|
||||
return insights[index] || '模型正在理解这个词的上下文关系。'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.attention-mechanism-demo {
|
||||
margin: 1rem 0;
|
||||
padding: 1.5rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
text-align: center;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.demo-header p {
|
||||
margin: 0;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.sentence-container {
|
||||
background: var(--vp-c-bg);
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.sentence {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
justify-content: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.word-token {
|
||||
padding: 0.5rem 1rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
user-select: none;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.word-token:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.word-token.active {
|
||||
background: var(--vp-c-brand);
|
||||
border-color: var(--vp-c-brand);
|
||||
color: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.attention-heatmap {
|
||||
min-height: 150px;
|
||||
}
|
||||
|
||||
.attention-bar {
|
||||
margin-bottom: 0.75rem;
|
||||
padding: 0.5rem 1rem;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.2);
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.25);
|
||||
border-radius: 4px;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.attention-bar.highlight {
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.35);
|
||||
border-color: rgba(var(--vp-c-brand-rgb), 0.4);
|
||||
}
|
||||
|
||||
.attention-label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.explanation-panel {
|
||||
background: var(--vp-c-bg);
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.explanation-content h5 {
|
||||
margin: 0 0 1rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.explanation-content p {
|
||||
margin-bottom: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.explanation-content ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 1rem 0;
|
||||
}
|
||||
|
||||
.explanation-content li {
|
||||
padding: 0.5rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin-bottom: 0.5rem;
|
||||
border-radius: 4px;
|
||||
border-left: 3px solid var(--vp-c-brand);
|
||||
font-size: 0.875rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.insight {
|
||||
padding: 1rem;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.08);
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.15);
|
||||
border-radius: 6px;
|
||||
color: var(--vp-c-text-1);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,383 @@
|
||||
<template>
|
||||
<div class="backpropagation-demo">
|
||||
<div class="demo-header">
|
||||
<h4>🔄 反向传播演示</h4>
|
||||
<p>观察神经网络如何通过误差反向调整权重</p>
|
||||
</div>
|
||||
|
||||
<div class="demo-content">
|
||||
<div class="network-view">
|
||||
<svg class="network-svg" viewBox="0 0 600 300">
|
||||
<!-- Layers visualization -->
|
||||
<g v-for="(layer, lIndex) in 3" :key="lIndex">
|
||||
<text :x="100 + lIndex * 200" y="20" text-anchor="middle" class="layer-label">
|
||||
{{ lIndex === 0 ? '输入层' : lIndex === 1 ? '隐藏层' : '输出层' }}
|
||||
</text>
|
||||
|
||||
<circle
|
||||
v-for="n in 3"
|
||||
:key="`${lIndex}-${n}`"
|
||||
:cx="100 + lIndex * 200"
|
||||
:cy="60 + n * 70"
|
||||
:r="25"
|
||||
:class="['neuron', getNeuronClass(lIndex, n)]"
|
||||
/>
|
||||
</g>
|
||||
|
||||
<!-- Connections with error flow -->
|
||||
<line
|
||||
v-for="conn in connections"
|
||||
:key="conn.id"
|
||||
:x1="conn.x1"
|
||||
:y1="conn.y1"
|
||||
:x2="conn.x2"
|
||||
:y2="conn.y2"
|
||||
:stroke="conn.color"
|
||||
:stroke-width="conn.width"
|
||||
:opacity="conn.opacity"
|
||||
class="connection"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="controls-panel">
|
||||
<div class="step-indicator">
|
||||
<div
|
||||
v-for="(step, index) in steps"
|
||||
:key="index"
|
||||
:class="['step', { active: currentStep === index, completed: currentStep > index }]"
|
||||
>
|
||||
<div class="step-number">{{ index + 1 }}</div>
|
||||
<div class="step-label">{{ step }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="error-display">
|
||||
<div class="error-value">
|
||||
误差: {{ errorValue.toFixed(4) }}
|
||||
</div>
|
||||
<div class="error-bar">
|
||||
<div class="error-fill" :style="{ width: (errorValue * 100) + '%' }"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button @click="nextStep" class="step-btn" :disabled="currentStep >= 4">
|
||||
{{ currentStep < 4 ? '下一步 ▶' : '完成 ✓' }}
|
||||
</button>
|
||||
|
||||
<button @click="resetDemo" class="reset-btn">
|
||||
🔄 重置演示
|
||||
</button>
|
||||
|
||||
<div class="explanation">
|
||||
<p><strong>当前步骤:</strong> {{ explanations[currentStep] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const currentStep = ref(0)
|
||||
const errorValue = ref(0.95)
|
||||
const steps = ['前向传播', '计算误差', '反向传播', '更新权重']
|
||||
const explanations = [
|
||||
'输入数据通过各层传递,得到预测输出',
|
||||
'对比预测值和真实值,计算误差',
|
||||
'将误差从输出层反向传递到各层',
|
||||
'根据误差梯度调整每个神经元的权重'
|
||||
]
|
||||
|
||||
const connections = ref([])
|
||||
|
||||
// 初始化连接
|
||||
const initConnections = () => {
|
||||
const conns = []
|
||||
for (let l = 0; l < 2; l++) {
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
for (let j = 1; j <= 3; j++) {
|
||||
conns.push({
|
||||
id: `${l}-${i}-${j}`,
|
||||
x1: 100 + l * 200,
|
||||
y1: 60 + i * 70,
|
||||
x2: 100 + (l + 1) * 200,
|
||||
y2: 60 + j * 70,
|
||||
color: 'var(--vp-c-divider)',
|
||||
width: 1,
|
||||
opacity: 0.3,
|
||||
active: false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
connections.value = conns
|
||||
}
|
||||
|
||||
const getNeuronClass = (layer, neuron) => {
|
||||
if (currentStep.value === 0 && layer === 0) return 'active'
|
||||
if (currentStep.value === 1 && layer === 2) return 'error'
|
||||
if (currentStep.value >= 2) return 'updated'
|
||||
return ''
|
||||
}
|
||||
|
||||
const nextStep = () => {
|
||||
if (currentStep.value < 4) {
|
||||
currentStep.value++
|
||||
|
||||
// 模拟误差减小
|
||||
if (currentStep.value === 2) {
|
||||
errorValue.value = 0.95
|
||||
} else if (currentStep.value === 3) {
|
||||
errorValue.value = 0.65
|
||||
} else if (currentStep.value === 4) {
|
||||
errorValue.value = 0.32
|
||||
}
|
||||
|
||||
// 更新连接显示
|
||||
updateConnections()
|
||||
}
|
||||
}
|
||||
|
||||
const updateConnections = () => {
|
||||
if (currentStep.value >= 2) {
|
||||
connections.value.forEach((conn) => {
|
||||
conn.color = 'var(--vp-c-brand)'
|
||||
conn.width = 2
|
||||
conn.opacity = 0.6
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const resetDemo = () => {
|
||||
currentStep.value = 0
|
||||
errorValue.value = 0.95
|
||||
initConnections()
|
||||
}
|
||||
|
||||
// 初始化
|
||||
initConnections()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.backpropagation-demo {
|
||||
margin: 1rem 0;
|
||||
padding: 1.5rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
text-align: center;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.demo-header p {
|
||||
margin: 0;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.demo-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.network-view {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.network-svg {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.layer-label {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
fill: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.neuron {
|
||||
fill: var(--vp-c-bg-alt);
|
||||
stroke: var(--vp-c-divider);
|
||||
stroke-width: 2;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.neuron.active {
|
||||
fill: var(--vp-c-green-1, #22c55e);
|
||||
stroke: var(--vp-c-green-2, #16a34a);
|
||||
}
|
||||
|
||||
.neuron.error {
|
||||
fill: var(--vp-c-red-1, #ef4444);
|
||||
stroke: var(--vp-c-red-2, #dc2626);
|
||||
}
|
||||
|
||||
.neuron.updated {
|
||||
fill: var(--vp-c-brand);
|
||||
stroke: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.connection {
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.controls-panel {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.step-indicator {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.step {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
opacity: 0.4;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.step.active,
|
||||
.step.completed {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.step-number {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin: 0 auto 0.5rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
font-size: 0.875rem;
|
||||
color: var(--vp-c-text-2);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.step.active .step-number {
|
||||
background: var(--vp-c-brand);
|
||||
color: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.step.completed .step-number {
|
||||
background: var(--vp-c-green-1, #22c55e);
|
||||
color: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.step-label {
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.error-display {
|
||||
margin-bottom: 1.5rem;
|
||||
padding: 1rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.error-value {
|
||||
font-weight: 700;
|
||||
color: var(--vp-c-red-1, #ef4444);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.error-bar {
|
||||
height: 8px;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.error-fill {
|
||||
height: 100%;
|
||||
background: var(--vp-c-red-1, #ef4444);
|
||||
transition: width 0.5s ease;
|
||||
}
|
||||
|
||||
.step-btn,
|
||||
.reset-btn {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.step-btn {
|
||||
background: var(--vp-c-brand);
|
||||
border-color: var(--vp-c-brand);
|
||||
color: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.step-btn:hover:not(:disabled) {
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.step-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.reset-btn:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.explanation {
|
||||
padding: 1rem;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.08);
|
||||
border-left: 4px solid var(--vp-c-brand);
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.15);
|
||||
}
|
||||
|
||||
.explanation p {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.6;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.explanation strong {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.demo-content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,760 @@
|
||||
<template>
|
||||
<div class="combinatorial-explosion-demo">
|
||||
<div class="demo-container">
|
||||
<div class="controls-panel">
|
||||
<h4>🎯 组合爆炸模拟器</h4>
|
||||
<p class="subtitle">亲手体验"规则指数增长"的恐怖</p>
|
||||
|
||||
<div class="control-group">
|
||||
<label>
|
||||
<span class="label-icon">🎨</span>
|
||||
物体特征数量:{{ featureCount }}
|
||||
</label>
|
||||
<input
|
||||
v-model.number="featureCount"
|
||||
type="range"
|
||||
min="2"
|
||||
max="6"
|
||||
step="1"
|
||||
class="feature-slider"
|
||||
/>
|
||||
<div class="feature-preview">
|
||||
<span
|
||||
v-for="i in featureCount"
|
||||
:key="i"
|
||||
class="feature-tag"
|
||||
:style="{ background: getFeatureColor(i) }"
|
||||
>
|
||||
特征{{ i }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>
|
||||
<span class="label-icon">🔢</span>
|
||||
每个特征的可能值:{{ valuesPerFeature }}
|
||||
</label>
|
||||
<input
|
||||
v-model.number="valuesPerFeature"
|
||||
type="range"
|
||||
min="2"
|
||||
max="4"
|
||||
step="1"
|
||||
class="value-slider"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<button @click="addRule" class="add-rule-btn" :disabled="ruleCount >= maxRules">
|
||||
✨ 添加规则 ({{ ruleCount }}/{{ maxRules }})
|
||||
</button>
|
||||
<button @click="autoGenerate" class="auto-btn" :disabled="autoGenerating">
|
||||
⚡ 自动生成
|
||||
</button>
|
||||
<button @click="resetRules" class="reset-btn">
|
||||
🔄 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="visualization-panel">
|
||||
<div class="counter-display">
|
||||
<div class="counter-label">需要的规则总数</div>
|
||||
<transition name="count-update" mode="out-in">
|
||||
<div :key="totalRules" class="counter-value">{{ formatNumber(totalRules) }}</div>
|
||||
</transition>
|
||||
<div class="counter-formula">
|
||||
= {{ valuesPerFeature }}<sup>{{ featureCount }}</sup> =
|
||||
<span class="highlight">{{ totalRules }}</span>
|
||||
</div>
|
||||
<div class="complexity-badge" :class="getComplexityLevel(totalRules)">
|
||||
{{ getComplexityLabel(totalRules) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rules-container">
|
||||
<transition-group name="rule-pop" tag="div" class="rules-grid">
|
||||
<div
|
||||
v-for="(rule, index) in displayedRules"
|
||||
:key="rule.id"
|
||||
class="rule-card"
|
||||
:style="{ borderColor: rule.color }"
|
||||
>
|
||||
<div class="rule-number">#{{ index + 1 }}</div>
|
||||
<div class="rule-content">
|
||||
<code>{{ rule.text }}</code>
|
||||
</div>
|
||||
<div class="rule-visual" :style="{ background: rule.gradient }"></div>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
|
||||
<transition name="warning-fade">
|
||||
<div v-if="showWarning" class="warning-message">
|
||||
<div class="warning-icon">💥</div>
|
||||
<div class="warning-content">
|
||||
<h5>组合爆炸!</h5>
|
||||
<p>
|
||||
即使只有 <strong>{{ featureCount }}</strong> 个特征,每个特征
|
||||
<strong>{{ valuesPerFeature }}</strong> 种可能,也需要
|
||||
<strong>{{ formatNumber(totalRules) }}</strong> 条规则!
|
||||
</p>
|
||||
<p>
|
||||
这就是为什么<strong>基于规则的 AI</strong> 无法处理复杂现实——
|
||||
规则数量呈<strong>指数级增长</strong>,根本写不完!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="comparison-box">
|
||||
<h5>📊 对比:人类 vs 规则系统</h5>
|
||||
<div class="comparison-grid">
|
||||
<div class="comparison-item">
|
||||
<div class="comparison-icon">🧠</div>
|
||||
<div class="comparison-text">
|
||||
<strong>人类识别猫</strong>
|
||||
<p>看到 → 瞬间识别(无需列举规则)</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comparison-arrow">→</div>
|
||||
<div class="comparison-item">
|
||||
<div class="comparison-icon">🤖</div>
|
||||
<div class="comparison-text">
|
||||
<strong>规则系统识别猫</strong>
|
||||
<p>需要 {{ formatNumber(totalRules) }} 条规则</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="insight-box">
|
||||
<h5>💡 关键洞察</h5>
|
||||
<p>
|
||||
<strong>符号主义 AI 的致命弱点</strong>:现实世界的特征组合是无限的。
|
||||
即使是简单的"识别猫",也需要考虑:
|
||||
</p>
|
||||
<ul class="feature-list">
|
||||
<li>形状:圆脸、尖脸...</li>
|
||||
<li>耳朵:立耳、折耳...</li>
|
||||
<li>毛色:黑、白、橘、花纹...</li>
|
||||
<li>体型:胖、瘦、中等...</li>
|
||||
<li>姿态:站立、趴下、跳跃...</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
<p class="conclusion">
|
||||
<strong>结论</strong>:规则永远写不完,这就是为什么我们需要<strong>机器学习</strong>!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
|
||||
const featureCount = ref(3)
|
||||
const valuesPerFeature = ref(3)
|
||||
const ruleCount = ref(0)
|
||||
const ruleIdCounter = ref(0)
|
||||
const autoGenerating = ref(false)
|
||||
const displayedRules = ref([])
|
||||
const maxRules = 20
|
||||
|
||||
// Use theme colors (works for dark/light) instead of hardcoded hex.
|
||||
const featureColors = [
|
||||
'rgba(var(--vp-c-brand-rgb), 0.18)',
|
||||
'rgba(var(--vp-c-brand-rgb), 0.24)',
|
||||
'rgba(var(--vp-c-brand-rgb), 0.3)',
|
||||
'rgba(var(--vp-c-brand-rgb), 0.36)',
|
||||
'rgba(var(--vp-c-brand-rgb), 0.42)',
|
||||
'rgba(var(--vp-c-brand-rgb), 0.48)'
|
||||
]
|
||||
|
||||
const totalRules = computed(() => {
|
||||
return Math.pow(valuesPerFeature.value, featureCount.value)
|
||||
})
|
||||
|
||||
const showWarning = computed(() => {
|
||||
return ruleCount.value >= maxRules || totalRules.value > 50
|
||||
})
|
||||
|
||||
const getFeatureColor = (index) => {
|
||||
return featureColors[(index - 1) % featureColors.length]
|
||||
}
|
||||
|
||||
const features = computed(() => {
|
||||
const featureNames = ['形状', '颜色', '大小', '纹理', '尾巴', '耳朵']
|
||||
return featureNames.slice(0, featureCount.value)
|
||||
})
|
||||
|
||||
const valueOptions = computed(() => {
|
||||
const options = {
|
||||
2: ['小', '大'],
|
||||
3: ['小', '中', '大'],
|
||||
4: ['很小', '小', '大', '很大']
|
||||
}
|
||||
return options[valuesPerFeature.value] || options[3]
|
||||
})
|
||||
|
||||
const generateRuleText = () => {
|
||||
const conditions = features.value.map((feature, index) => {
|
||||
const value = valueOptions.value[Math.floor(Math.random() * valuesPerFeature.value)]
|
||||
return `${feature}=${value}`
|
||||
})
|
||||
return `IF ${conditions.join(' AND ')} THEN ...`
|
||||
}
|
||||
|
||||
const generateColor = () => {
|
||||
// Keep visuals subtle and theme-consistent; avoid heavy gradients.
|
||||
return 'rgba(var(--vp-c-brand-rgb), 0.12)'
|
||||
}
|
||||
|
||||
const addRule = () => {
|
||||
if (ruleCount.value < maxRules) {
|
||||
displayedRules.value.push({
|
||||
id: ruleIdCounter.value++,
|
||||
text: generateRuleText(),
|
||||
color: getFeatureColor(Math.floor(Math.random() * featureCount.value) + 1),
|
||||
gradient: generateColor()
|
||||
})
|
||||
ruleCount.value++
|
||||
}
|
||||
}
|
||||
|
||||
const autoGenerate = async () => {
|
||||
if (autoGenerating.value) return
|
||||
|
||||
autoGenerating.value = true
|
||||
const interval = setInterval(() => {
|
||||
if (ruleCount.value >= maxRules) {
|
||||
clearInterval(interval)
|
||||
autoGenerating.value = false
|
||||
} else {
|
||||
addRule()
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
const resetRules = () => {
|
||||
displayedRules.value = []
|
||||
ruleCount.value = 0
|
||||
autoGenerating.value = false
|
||||
}
|
||||
|
||||
const formatNumber = (num) => {
|
||||
if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M'
|
||||
if (num >= 1000) return (num / 1000).toFixed(1) + 'K'
|
||||
return num.toString()
|
||||
}
|
||||
|
||||
const getComplexityLevel = (num) => {
|
||||
if (num < 10) return 'low'
|
||||
if (num < 100) return 'medium'
|
||||
if (num < 1000) return 'high'
|
||||
return 'extreme'
|
||||
}
|
||||
|
||||
const getComplexityLabel = (num) => {
|
||||
if (num < 10) return '😊 简单'
|
||||
if (num < 100) return '😐 复杂'
|
||||
if (num < 1000) return '😰 非常复杂'
|
||||
return '😱 指数爆炸'
|
||||
}
|
||||
|
||||
// 重置规则当特征数变化时
|
||||
watch([featureCount, valuesPerFeature], () => {
|
||||
resetRules()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.combinatorial-explosion-demo {
|
||||
margin: 1rem 0;
|
||||
padding: 1.5rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.2fr;
|
||||
gap: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.controls-panel {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
color: var(--vp-c-text-1);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.controls-panel h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.875rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.control-group {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.control-group label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.75rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.label-icon {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.feature-slider,
|
||||
.value-slider {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
background: var(--vp-c-divider);
|
||||
outline: none;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.feature-slider::-webkit-slider-thumb,
|
||||
.value-slider::-webkit-slider-thumb {
|
||||
appearance: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: var(--vp-c-brand);
|
||||
cursor: pointer;
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.25);
|
||||
}
|
||||
|
||||
.feature-preview {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.feature-tag {
|
||||
padding: 0.35rem 0.75rem;
|
||||
color: var(--vp-c-bg);
|
||||
border-radius: 20px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
background: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.add-rule-btn,
|
||||
.auto-btn,
|
||||
.reset-btn {
|
||||
width: 100%;
|
||||
padding: 0.875rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.add-rule-btn {
|
||||
background: var(--vp-c-brand);
|
||||
border-color: var(--vp-c-brand);
|
||||
color: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.add-rule-btn:hover:not(:disabled) {
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.add-rule-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.auto-btn {
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.auto-btn:hover:not(:disabled) {
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.reset-btn:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.visualization-panel {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
color: var(--vp-c-text-1);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.counter-display {
|
||||
text-align: center;
|
||||
padding: 2rem 1.5rem;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.08);
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.15);
|
||||
color: var(--vp-c-text-1);
|
||||
border-radius: 12px;
|
||||
margin-bottom: 1.5rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.counter-display::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -50%;
|
||||
left: -50%;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
background: radial-gradient(
|
||||
circle,
|
||||
rgba(var(--vp-c-brand-rgb), 0.08) 0%,
|
||||
transparent 70%
|
||||
);
|
||||
animation: pulse 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { transform: scale(1); opacity: 0.5; }
|
||||
50% { transform: scale(1.1); opacity: 0.8; }
|
||||
}
|
||||
|
||||
.counter-label {
|
||||
font-size: 0.875rem;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 0.5rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.counter-value {
|
||||
font-size: 3.5rem;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
margin-bottom: 0.75rem;
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.counter-formula {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
font-family: var(--vp-font-family-mono);
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.counter-formula .highlight {
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: 700;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.complexity-badge {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1.25rem;
|
||||
border-radius: 25px;
|
||||
font-weight: 700;
|
||||
font-size: 0.875rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.complexity-badge.low {
|
||||
border-color: var(--vp-c-green-1, #22c55e);
|
||||
}
|
||||
|
||||
.complexity-badge.medium {
|
||||
border-color: var(--vp-c-yellow-1, #f59e0b);
|
||||
}
|
||||
|
||||
.complexity-badge.high {
|
||||
border-color: var(--vp-c-yellow-1, #f59e0b);
|
||||
}
|
||||
|
||||
.complexity-badge.extreme {
|
||||
border-color: var(--vp-c-red-1, #ef4444);
|
||||
animation: shake 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0%, 100% { transform: translateX(0); }
|
||||
25% { transform: translateX(-5px); }
|
||||
75% { transform: translateX(5px); }
|
||||
}
|
||||
|
||||
.rules-container {
|
||||
min-height: 300px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.rules-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.rule-card {
|
||||
position: relative;
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-left: 4px solid var(--vp-c-brand);
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.rule-number {
|
||||
font-size: 0.65rem;
|
||||
font-weight: 700;
|
||||
color: var(--vp-c-brand);
|
||||
margin-bottom: 0.35rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.rule-content code {
|
||||
display: block;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 0.7rem;
|
||||
line-height: 1.4;
|
||||
word-break: break-word;
|
||||
font-family: var(--vp-font-family-mono);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
padding: 0.35rem;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.rule-visual {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
opacity: 0.3;
|
||||
border-radius: 0 6px 0 6px;
|
||||
}
|
||||
|
||||
.warning-message {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
padding: 1.25rem 1.5rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-left: 4px solid var(--vp-c-yellow-1, #f59e0b);
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.warning-icon {
|
||||
font-size: 2.5rem;
|
||||
flex-shrink: 0;
|
||||
animation: bounce 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-10px); }
|
||||
}
|
||||
|
||||
.warning-content h5 {
|
||||
margin: 0 0 0.75rem 0;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.warning-content p {
|
||||
margin: 0 0 0.5rem 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.warning-content strong {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.comparison-box {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
color: var(--vp-c-text-1);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.comparison-box h5 {
|
||||
margin: 0 0 1.25rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.comparison-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.comparison-item {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.comparison-icon {
|
||||
font-size: 2.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.comparison-text strong {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.comparison-text p {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.comparison-arrow {
|
||||
font-size: 2rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.insight-box {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
color: var(--vp-c-text-1);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.insight-box h5 {
|
||||
margin: 0 0 1rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.insight-box p {
|
||||
margin: 0 0 1rem 0;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.insight-box .conclusion {
|
||||
padding: 1rem;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.08);
|
||||
border-left: 4px solid var(--vp-c-brand);
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.15);
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.feature-list li {
|
||||
padding: 0.5rem 0.5rem 0.5rem 2rem;
|
||||
position: relative;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.feature-list li::before {
|
||||
content: '✦';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* Transitions */
|
||||
.count-update-enter-active,
|
||||
.count-update-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.count-update-enter-from {
|
||||
opacity: 0;
|
||||
transform: scale(0.5);
|
||||
}
|
||||
|
||||
.count-update-leave-to {
|
||||
opacity: 0;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
|
||||
.rule-pop-enter-active {
|
||||
transition: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||
}
|
||||
|
||||
.rule-pop-enter-from {
|
||||
opacity: 0;
|
||||
transform: scale(0.3) rotate(-10deg);
|
||||
}
|
||||
|
||||
.warning-fade-enter-active,
|
||||
.warning-fade-leave-active {
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.warning-fade-enter-from,
|
||||
.warning-fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.demo-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.comparison-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.comparison-arrow {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+401
@@ -0,0 +1,401 @@
|
||||
<template>
|
||||
<div class="discriminative-vs-generative-demo">
|
||||
<div class="demo-header">
|
||||
<h4>🎯 判别式 vs 生成式 AI</h4>
|
||||
<p>理解两种不同的 AI 范式</p>
|
||||
</div>
|
||||
|
||||
<div class="comparison-container">
|
||||
<!-- Discriminative AI -->
|
||||
<div class="ai-panel discriminative" :class="{ active: mode === 'discriminative' }" @click="mode = 'discriminative'">
|
||||
<div class="panel-header">
|
||||
<div class="icon">🔍</div>
|
||||
<h5>判别式 AI</h5>
|
||||
<div class="tag">分类/识别</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-content">
|
||||
<div class="input-output">
|
||||
<div class="io-box input">
|
||||
<div class="io-label">输入</div>
|
||||
<div class="io-content">
|
||||
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60' viewBox='0 0 60 60'%3E%3Crect width='60' height='60' fill='%2348bb78'/%3E%3Ctext x='30' y='35' text-anchor='middle' fill='white' font-size='12'%3E猫图%3C/text%3E%3C/svg%3E" alt="cat" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow">↓</div>
|
||||
|
||||
<div class="io-box output">
|
||||
<div class="io-label">输出</div>
|
||||
<div class="io-content">
|
||||
<div class="result-tag">这是猫</div>
|
||||
<div class="probability">置信度: 98%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="examples">
|
||||
<h6>典型应用:</h6>
|
||||
<div class="example-tags">
|
||||
<span class="tag">图像分类</span>
|
||||
<span class="tag">垃圾邮件过滤</span>
|
||||
<span class="tag">疾病诊断</span>
|
||||
<span class="tag">人脸识别</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Generative AI -->
|
||||
<div class="ai-panel generative" :class="{ active: mode === 'generative' }" @click="mode = 'generative'">
|
||||
<div class="panel-header">
|
||||
<div class="icon">✨</div>
|
||||
<h5>生成式 AI</h5>
|
||||
<div class="tag">创造/生成</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-content">
|
||||
<div class="input-output">
|
||||
<div class="io-box input">
|
||||
<div class="io-label">输入</div>
|
||||
<div class="io-content">
|
||||
<div class="prompt-text">"一只戴墨镜的猫"</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow">↓</div>
|
||||
|
||||
<div class="io-box output">
|
||||
<div class="io-label">输出</div>
|
||||
<div class="io-content">
|
||||
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='60' viewBox='0 0 80 60'%3E%3Crect width='80' height='60' fill='%23667eea'/%3E%3Ccircle cx='30' cy='25' r='3' fill='black'/%3E%3Cline x1='27' y1='25' x2='33' y2='25' stroke='black' stroke-width='1'/%3E%3Cellipse cx='30' cy='30' rx='8' ry='6' fill='white'/%3E%3Ccircle cx='30' cy='28' r='2' fill='black'/%3E%3Cpath d='M 22 20 Q 30 15 38 20' stroke='orange' stroke-width='2' fill='none'/%3E%3Cpath d='M 38 35 Q 50 30 55 40' stroke='gray' stroke-width='3' fill='none'/%3E%3C/svg%3E" alt="generated cat" />
|
||||
<div class="generated-label">生成图像 ✓</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="examples">
|
||||
<h6>典型应用:</h6>
|
||||
<div class="example-tags">
|
||||
<span class="tag">ChatGPT</span>
|
||||
<span class="tag">Midjourney</span>
|
||||
<span class="tag">代码生成</span>
|
||||
<span class="tag">音乐创作</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="comparison-table">
|
||||
<h5>📊 核心差异对比</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>维度</th>
|
||||
<th>判别式 AI</th>
|
||||
<th>生成式 AI</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>目标</strong></td>
|
||||
<td>区分、分类、识别</td>
|
||||
<td>创造、生成新内容</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>输入</strong></td>
|
||||
<td>数据(图像、文本等)</td>
|
||||
<td>提示词、噪声、种子</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>输出</strong></td>
|
||||
<td>标签、类别、概率</td>
|
||||
<td>新的数据(文本、图像等)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>学习方式</strong></td>
|
||||
<td>学习 P(标签|数据)</td>
|
||||
<td>学习 P(数据)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>代表模型</strong></td>
|
||||
<td>ResNet, BERT(分类)</td>
|
||||
<td>GPT, DALL-E, Stable Diffusion</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="key-insight">
|
||||
<h5>💡 关键洞察</h5>
|
||||
<p>
|
||||
<strong>判别式 AI</strong>就像考试中的"选择题"——从给定选项中选出正确答案。<br>
|
||||
<strong>生成式 AI</strong>就像考试中的"简答题"——自己创造出全新的答案。
|
||||
</p>
|
||||
<p class="note">
|
||||
从 2020 年代开始,生成式 AI 迅速崛起,成为人工智能的主流方向。
|
||||
GPT、Midjourney 等模型展现出了惊人的创造力,开启了 AI 2.0 时代。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const mode = ref('discriminative')
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.discriminative-vs-generative-demo {
|
||||
margin: 1rem 0;
|
||||
padding: 1.5rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.demo-header p {
|
||||
margin: 0;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.comparison-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.ai-panel {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.ai-panel:hover {
|
||||
border-color: rgba(var(--vp-c-brand-rgb), 0.35);
|
||||
}
|
||||
|
||||
.ai-panel.active {
|
||||
border-color: var(--vp-c-brand);
|
||||
box-shadow: 0 0 0 3px rgba(var(--vp-c-brand-rgb), 0.12);
|
||||
}
|
||||
|
||||
.ai-panel.discriminative {
|
||||
--ev-panel-accent: var(--vp-c-green-1, #22c55e);
|
||||
}
|
||||
|
||||
.ai-panel.discriminative.active {
|
||||
border-color: var(--ev-panel-accent);
|
||||
}
|
||||
|
||||
.ai-panel.generative {
|
||||
--ev-panel-accent: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.ai-panel.generative.active {
|
||||
border-color: var(--ev-panel-accent);
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1.5rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.panel-header h5 {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
font-size: 1.25rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.tag {
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.08);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.input-output {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.io-box {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.io-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.5rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.io-content {
|
||||
padding: 1rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
min-height: 80px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.io-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.result-tag,
|
||||
.prompt-text {
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.probability {
|
||||
font-size: 0.875rem;
|
||||
color: var(--vp-c-green-1, #22c55e);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.generated-label {
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
text-align: center;
|
||||
font-size: 1.5rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.examples h6 {
|
||||
margin: 0 0 0.75rem 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.example-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.example-tags .tag {
|
||||
padding: 0.25rem 0.75rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 15px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.comparison-table {
|
||||
background: var(--vp-c-bg);
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.comparison-table h5 {
|
||||
margin: 0 0 1rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
thead th {
|
||||
text-align: left;
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg-alt);
|
||||
color: var(--vp-c-text-1);
|
||||
font-weight: 600;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
tbody td {
|
||||
padding: 0.75rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.key-insight {
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.08);
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.15);
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.key-insight h5 {
|
||||
margin: 0 0 1rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.key-insight p {
|
||||
margin: 0 0 1rem 0;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.key-insight .note {
|
||||
font-size: 0.875rem;
|
||||
color: var(--vp-c-text-2);
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.comparison-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,468 @@
|
||||
<template>
|
||||
<div class="gpt-evolution-demo">
|
||||
<div class="demo-header">
|
||||
<h4>🚀 GPT 进化历程</h4>
|
||||
<p>从 GPT-1 到 GPT-4 的演进之路</p>
|
||||
</div>
|
||||
|
||||
<div class="timeline-container">
|
||||
<div class="timeline-track"></div>
|
||||
|
||||
<div
|
||||
v-for="(model, index) in gptModels"
|
||||
:key="index"
|
||||
class="timeline-item"
|
||||
:class="{ active: activeModel === index }"
|
||||
@click="selectModel(index)"
|
||||
>
|
||||
<div class="timeline-marker">
|
||||
<div class="marker-dot"></div>
|
||||
</div>
|
||||
<div class="timeline-content">
|
||||
<div class="model-year">{{ model.year }}</div>
|
||||
<div class="model-name">{{ model.name }}</div>
|
||||
<div class="model-stats">
|
||||
<span class="stat">📊 {{ model.parameters }}</span>
|
||||
<span class="stat">🎯 {{ model.context }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<transition name="fade-slide">
|
||||
<div v-if="activeModel !== null" class="model-details">
|
||||
<div class="details-header">
|
||||
<h5>{{ gptModels[activeModel].name }}</h5>
|
||||
<span class="year-badge">{{ gptModels[activeModel].year }}</span>
|
||||
</div>
|
||||
|
||||
<div class="details-grid">
|
||||
<div class="detail-card">
|
||||
<div class="card-label">参数量</div>
|
||||
<div class="card-value">{{ gptModels[activeModel].parameters }}</div>
|
||||
<div class="card-note">{{ gptModels[activeModel].paramDetail }}</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<div class="card-label">上下文窗口</div>
|
||||
<div class="card-value">{{ gptModels[activeModel].context }}</div>
|
||||
<div class="card-note">{{ gptModels[activeModel].contextDetail }}</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<div class="card-label">主要能力</div>
|
||||
<div class="card-value">{{ gptModels[activeModel].capability }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="model-description">
|
||||
<h6>📝 模型简介</h6>
|
||||
<p>{{ gptModels[activeModel].description }}</p>
|
||||
</div>
|
||||
|
||||
<div class="model-milestones">
|
||||
<h6>🎯 关键里程碑</h6>
|
||||
<ul>
|
||||
<li v-for="(milestone, i) in gptModels[activeModel].milestones" :key="i">
|
||||
{{ milestone }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<div class="evolution-insight">
|
||||
<h5>💡 进化趋势</h5>
|
||||
<div class="trend-grid">
|
||||
<div class="trend-item">
|
||||
<div class="trend-icon">📈</div>
|
||||
<div class="trend-text">参数量从 1.17 亿增长到万亿级别</div>
|
||||
</div>
|
||||
<div class="trend-item">
|
||||
<div class="trend-icon">🧠</div>
|
||||
<div class="trend-text">从文本生成到多模态(图像、音频、视频)</div>
|
||||
</div>
|
||||
<div class="trend-item">
|
||||
<div class="trend-icon">🎯</div>
|
||||
<div class="trend-text">上下文窗口从 512 tokens 扩展到 128k+</div>
|
||||
</div>
|
||||
<div class="trend-item">
|
||||
<div class="trend-icon">🌐</div>
|
||||
<div class="trend-text">从单语言到多语言,从通用到专业领域</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const activeModel = ref(0)
|
||||
|
||||
const gptModels = ref([
|
||||
{
|
||||
name: 'GPT-1',
|
||||
year: '2018',
|
||||
parameters: '1.17 亿',
|
||||
paramDetail: '117M',
|
||||
context: '512 tokens',
|
||||
contextDetail: '约 384 英文单词',
|
||||
capability: '文本生成',
|
||||
description: 'OpenAI 发布的首个 GPT 模型,证明了生成式预训练的可行性。它采用"预训练 + 微调"范式,在无标注文本上学习语言模式。',
|
||||
milestones: [
|
||||
'首次验证 Transformer 架构在语言模型中的有效性',
|
||||
'引入生成式预训练方法',
|
||||
'为后续 GPT 系列奠定基础'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'GPT-2',
|
||||
year: '2019',
|
||||
parameters: '15 亿',
|
||||
paramDetail: '1.5B',
|
||||
context: '1024 tokens',
|
||||
contextDetail: '约 768 英文单词',
|
||||
capability: '高质量文本生成',
|
||||
description: 'GPT-2 的规模扩大了 13 倍,能够生成连贯、高质量的文本。由于担心滥用,OpenAI 最初只发布了缩小版本,引发广泛争议。',
|
||||
milestones: [
|
||||
'参数量突破 10 亿级别',
|
||||
'展现出惊人的零样本学习能力',
|
||||
"引发 AI 安全和滥用的讨论",
|
||||
'最终完整版本于 2019 年 11 月发布'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'GPT-3',
|
||||
year: '2020',
|
||||
parameters: '1750 亿',
|
||||
paramDetail: '175B',
|
||||
context: '2048 tokens',
|
||||
contextDetail: '约 1536 英文单词',
|
||||
capability: '少样本学习',
|
||||
description: 'GPT-3 是当时规模最大的语言模型,展现出强大的少样本和零样本学习能力。它证明了"规模就是一切"的假设,只需通过提示词就能完成各种任务。',
|
||||
milestones: [
|
||||
'参数量达到 1750 亿,比 GPT-2 增长 116 倍',
|
||||
'少样本学习能力震惊学术界',
|
||||
'催生了大量基于 API 的应用',
|
||||
'OpenAI 开始提供商业 API 服务'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'GPT-3.5',
|
||||
year: '2022',
|
||||
parameters: '未知',
|
||||
paramDetail: '估计 2000 亿+',
|
||||
context: '4096 tokens',
|
||||
contextDetail: '约 3072 英文单词',
|
||||
capability: '对话系统',
|
||||
description: 'GPT-3.5 在 GPT-3 基础上引入了对话训练和强化学习(RLHF),成为 ChatGPT 的基础模型。它能够进行自然、连贯的多轮对话,是 AI 历史上的重要里程碑。',
|
||||
milestones: [
|
||||
'引入人类反馈强化学习(RLHF)',
|
||||
'ChatGPT 发布,5 天用户破百万',
|
||||
'2 个月月活破亿,创历史记录',
|
||||
'掀起全球 AI 热潮'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'GPT-4',
|
||||
year: '2023',
|
||||
parameters: '未知',
|
||||
paramDetail: '估计 1.8 万亿',
|
||||
context: '8192-32768 tokens',
|
||||
contextDetail: '最多 50 页文档',
|
||||
capability: '多模态智能',
|
||||
description: 'GPT-4 是一个多模态大模型,能够处理文本、图像等多种输入。它在各项基准测试中接近人类水平,并在复杂推理、数学、编程等任务上表现出色。',
|
||||
milestones: [
|
||||
'首个大规模多模态模型',
|
||||
'在律师考试、奥数等高难度测试中表现出色',
|
||||
'支持更长上下文(最多 32k tokens)',
|
||||
'推出 GPT-4 Turbo,速度更快、价格更低'
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
const selectModel = (index) => {
|
||||
activeModel.value = index
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.gpt-evolution-demo {
|
||||
margin: 1rem 0;
|
||||
padding: 1.5rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.demo-header p {
|
||||
margin: 0;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.timeline-container {
|
||||
position: relative;
|
||||
padding: 1rem 0;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.timeline-track {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 4px;
|
||||
background: var(--vp-c-divider);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin-bottom: 1.5rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.timeline-item:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.timeline-item.active .marker-dot {
|
||||
background: var(--vp-c-brand);
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.timeline-marker {
|
||||
width: 44px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.marker-dot {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 50%;
|
||||
border: 3px solid var(--vp-c-divider);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.timeline-content {
|
||||
margin-left: 1rem;
|
||||
padding: 1rem 1.5rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.timeline-item.active .timeline-content {
|
||||
border-color: var(--vp-c-brand);
|
||||
box-shadow: 0 0 0 3px rgba(var(--vp-c-brand-rgb), 0.12);
|
||||
}
|
||||
|
||||
.model-year {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.model-name {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.model-stats {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.model-details {
|
||||
margin-bottom: 2rem;
|
||||
padding: 1.5rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.details-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.details-header h5 {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.year-badge {
|
||||
padding: 0.5rem 1rem;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.12);
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.2);
|
||||
color: var(--vp-c-brand);
|
||||
border-radius: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.details-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
padding: 1rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.5rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.card-note {
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.model-description,
|
||||
.model-milestones {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.model-description h6,
|
||||
.model-milestones h6 {
|
||||
margin: 0 0 0.75rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.model-description p {
|
||||
margin: 0;
|
||||
line-height: 1.8;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.model-milestones ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.model-milestones li {
|
||||
padding: 0.5rem 0.5rem 0.5rem 1.5rem;
|
||||
position: relative;
|
||||
line-height: 1.6;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.model-milestones li::before {
|
||||
content: '✓';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: var(--vp-c-green-1, #22c55e);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.evolution-insight {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.evolution-insight h5 {
|
||||
margin: 0 0 1rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.trend-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.trend-item {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.trend-icon {
|
||||
font-size: 1.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.trend-text {
|
||||
font-size: 0.875rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.fade-slide-enter-active,
|
||||
.fade-slide-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.fade-slide-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
.fade-slide-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.details-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.trend-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+390
@@ -0,0 +1,390 @@
|
||||
<template>
|
||||
<div class="neural-network-viz-demo">
|
||||
<div class="demo-header">
|
||||
<h4>🧠 神经网络可视化</h4>
|
||||
<p>观察数据如何在神经网络中流动</p>
|
||||
</div>
|
||||
|
||||
<div class="network-container">
|
||||
<svg ref="svgRef" class="network-svg" :width="svgWidth" :height="svgHeight">
|
||||
<defs>
|
||||
<linearGradient id="connectionGradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color: var(--vp-c-brand); stop-opacity: 0.15"
|
||||
/>
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color: var(--vp-c-brand); stop-opacity: 0.45"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- Connections -->
|
||||
<g class="connections">
|
||||
<line
|
||||
v-for="conn in connections"
|
||||
:key="conn.id"
|
||||
:x1="conn.x1"
|
||||
:y1="conn.y1"
|
||||
:x2="conn.x2"
|
||||
:y2="conn.y2"
|
||||
:stroke-width="conn.width"
|
||||
:opacity="conn.opacity"
|
||||
stroke="url(#connectionGradient)"
|
||||
class="connection-line"
|
||||
/>
|
||||
</g>
|
||||
|
||||
<!-- Neurons -->
|
||||
<g class="neurons">
|
||||
<g
|
||||
v-for="neuron in neurons"
|
||||
:key="neuron.id"
|
||||
:transform="`translate(${neuron.x}, ${neuron.y})`"
|
||||
class="neuron-group"
|
||||
:class="{ active: neuron.active, input: neuron.layer === 0, output: neuron.layer === layers.length - 1 }"
|
||||
>
|
||||
<circle
|
||||
:r="neuron.radius"
|
||||
class="neuron-circle"
|
||||
@click="activateNeuron(neuron)"
|
||||
/>
|
||||
<text
|
||||
v-if="neuron.label"
|
||||
y="30"
|
||||
text-anchor="middle"
|
||||
class="neuron-label"
|
||||
>
|
||||
{{ neuron.label }}
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="layer-info">
|
||||
<div
|
||||
v-for="(layer, index) in layerConfigs"
|
||||
:key="index"
|
||||
class="layer-card"
|
||||
:class="{ active: currentLayer === index }"
|
||||
@click="currentLayer = index"
|
||||
>
|
||||
<div class="layer-badge">{{ layer.name }}</div>
|
||||
<div class="layer-neurons">{{ layer.neurons }} 个神经元</div>
|
||||
<div class="layer-desc">{{ layer.desc }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<button @click="startForwardPropagation" class="action-btn">
|
||||
▶️ 前向传播
|
||||
</button>
|
||||
<button @click="resetNetwork" class="action-btn secondary">
|
||||
🔄 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
|
||||
const svgWidth = 800
|
||||
const svgHeight = 400
|
||||
const currentLayer = ref(0)
|
||||
const animationId = ref(null)
|
||||
|
||||
const layers = ref([4, 6, 6, 3]) // 输入层、2个隐藏层、输出层
|
||||
const layerConfigs = ref([
|
||||
{ name: '输入层', neurons: 4, desc: '接收原始数据(如图片像素)' },
|
||||
{ name: '隐藏层 1', neurons: 6, desc: '识别边缘和简单特征' },
|
||||
{ name: '隐藏层 2', neurons: 6, desc: '识别形状和复杂特征' },
|
||||
{ name: '输出层', neurons: 3, desc: '输出分类结果' }
|
||||
])
|
||||
|
||||
const neurons = ref([])
|
||||
const connections = ref([])
|
||||
|
||||
// 计算神经元位置
|
||||
const calculateNeurons = () => {
|
||||
neurons.value = []
|
||||
const layerSpacing = svgWidth / (layers.value.length + 1)
|
||||
|
||||
layers.value.forEach((neuronCount, layerIndex) => {
|
||||
const x = layerSpacing * (layerIndex + 1)
|
||||
const neuronSpacing = svgHeight / (neuronCount + 1)
|
||||
|
||||
for (let i = 0; i < neuronCount; i++) {
|
||||
const y = neuronSpacing * (i + 1)
|
||||
neurons.value.push({
|
||||
id: `${layerIndex}-${i}`,
|
||||
layer: layerIndex,
|
||||
x,
|
||||
y,
|
||||
radius: 20,
|
||||
active: false,
|
||||
label:
|
||||
layerIndex === 0
|
||||
? ['像素1', '像素2', '像素3', '像素4'][i]
|
||||
: layerIndex === layers.value.length - 1
|
||||
? ['猫', '狗', '鸟'][i]
|
||||
: ''
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 计算连接
|
||||
const calculateConnections = () => {
|
||||
connections.value = []
|
||||
let connId = 0
|
||||
|
||||
for (let l = 0; l < layers.value.length - 1; l++) {
|
||||
const currentLayerNeurons = neurons.value.filter((n) => n.layer === l)
|
||||
const nextLayerNeurons = neurons.value.filter((n) => n.layer === l + 1)
|
||||
|
||||
currentLayerNeurons.forEach((fromNeuron) => {
|
||||
nextLayerNeurons.forEach((toNeuron) => {
|
||||
connections.value.push({
|
||||
id: connId++,
|
||||
x1: fromNeuron.x,
|
||||
y1: fromNeuron.y,
|
||||
x2: toNeuron.x,
|
||||
y2: toNeuron.y,
|
||||
width: Math.random() * 2 + 0.5,
|
||||
opacity: 0.3,
|
||||
active: false
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const activateNeuron = (neuron) => {
|
||||
neuron.active = !neuron.active
|
||||
currentLayer.value = neuron.layer
|
||||
}
|
||||
|
||||
const startForwardPropagation = async () => {
|
||||
resetNetwork()
|
||||
|
||||
// 激活输入层
|
||||
const inputNeurons = neurons.value.filter((n) => n.layer === 0)
|
||||
inputNeurons.forEach((n) => {
|
||||
n.active = true
|
||||
n.radius = 25
|
||||
})
|
||||
currentLayer.value = 0
|
||||
|
||||
await sleep(500)
|
||||
|
||||
// 逐层激活
|
||||
for (let l = 1; l < layers.value.length; l++) {
|
||||
currentLayer.value = l
|
||||
const layerNeurons = neurons.value.filter((n) => n.layer === l)
|
||||
|
||||
layerNeurons.forEach((neuron) => {
|
||||
neuron.active = true
|
||||
neuron.radius = 25
|
||||
})
|
||||
|
||||
// 高亮连接
|
||||
connections.value.forEach((conn) => {
|
||||
const fromNeuron = neurons.value.find(
|
||||
(n) => Math.abs(n.x - conn.x1) < 1 && Math.abs(n.y - conn.y1) < 1
|
||||
)
|
||||
if (fromNeuron && fromNeuron.layer === l - 1 && fromNeuron.active) {
|
||||
conn.opacity = 0.8
|
||||
conn.width = 3
|
||||
}
|
||||
})
|
||||
|
||||
await sleep(600)
|
||||
}
|
||||
}
|
||||
|
||||
const resetNetwork = () => {
|
||||
neurons.value.forEach((n) => {
|
||||
n.active = false
|
||||
n.radius = 20
|
||||
})
|
||||
connections.value.forEach((conn) => {
|
||||
conn.opacity = 0.3
|
||||
conn.width = Math.random() * 2 + 0.5
|
||||
})
|
||||
currentLayer.value = 0
|
||||
}
|
||||
|
||||
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
||||
|
||||
onMounted(() => {
|
||||
calculateNeurons()
|
||||
calculateConnections()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.neural-network-viz-demo {
|
||||
margin: 1rem 0;
|
||||
padding: 1.5rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
text-align: center;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.demo-header p {
|
||||
margin: 0;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.network-container {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.network-svg {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
min-width: 600px;
|
||||
}
|
||||
|
||||
.connection-line {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.neuron-group {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.neuron-group:hover .neuron-circle {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.neuron-circle {
|
||||
fill: rgba(var(--vp-c-brand-rgb), 0.35);
|
||||
stroke: var(--vp-c-brand);
|
||||
stroke-width: 2;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.neuron-group.input .neuron-circle {
|
||||
fill: rgba(var(--vp-c-brand-rgb), 0.2);
|
||||
stroke: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.neuron-group.output .neuron-circle {
|
||||
fill: rgba(var(--vp-c-brand-rgb), 0.12);
|
||||
stroke: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.neuron-group.active .neuron-circle {
|
||||
stroke-width: 3;
|
||||
}
|
||||
|
||||
.neuron-label {
|
||||
font-size: 10px;
|
||||
fill: var(--vp-c-text-1);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.layer-info {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.layer-card {
|
||||
padding: 1rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.layer-card:hover {
|
||||
border-color: rgba(var(--vp-c-brand-rgb), 0.35);
|
||||
}
|
||||
|
||||
.layer-card.active {
|
||||
border-color: var(--vp-c-brand);
|
||||
box-shadow: 0 0 0 3px rgba(var(--vp-c-brand-rgb), 0.12);
|
||||
}
|
||||
|
||||
.layer-badge {
|
||||
font-weight: 700;
|
||||
color: var(--vp-c-brand);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.layer-neurons {
|
||||
font-size: 0.875rem;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.layer-desc {
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
padding: 0.75rem 2rem;
|
||||
background: var(--vp-c-brand);
|
||||
color: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-brand);
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.action-btn.secondary {
|
||||
background: var(--vp-c-bg);
|
||||
border-color: var(--vp-c-divider);
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.action-btn.secondary:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.layer-info {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -96,7 +96,7 @@ const output = computed(() => {
|
||||
.perceptron-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
background: white;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
overflow-x: auto;
|
||||
@@ -123,19 +123,20 @@ const output = computed(() => {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #94a3b8;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f1f5f9;
|
||||
background: var(--vp-c-bg);
|
||||
position: relative;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.output-node.active {
|
||||
background: #4ade80;
|
||||
border-color: #16a34a;
|
||||
color: white;
|
||||
background: var(--vp-c-brand);
|
||||
border-color: var(--vp-c-brand);
|
||||
color: var(--vp-c-bg);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -145,7 +146,7 @@ const output = computed(() => {
|
||||
top: -15px;
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
color: #64748b;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.val-input {
|
||||
@@ -169,7 +170,7 @@ const output = computed(() => {
|
||||
|
||||
.weight-line {
|
||||
height: 2px;
|
||||
background: #475569;
|
||||
background: var(--vp-c-text-2);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
@@ -184,9 +185,9 @@ const output = computed(() => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
background: white;
|
||||
background: var(--vp-c-bg);
|
||||
padding: 2px 4px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 4px;
|
||||
z-index: 2;
|
||||
}
|
||||
@@ -195,14 +196,14 @@ const output = computed(() => {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 50%;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
background: var(--vp-c-brand);
|
||||
color: var(--vp-c-bg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
box-shadow: 0 4px 10px rgba(59, 130, 246, 0.3);
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.35);
|
||||
}
|
||||
|
||||
.sum-part {
|
||||
@@ -218,11 +219,11 @@ const output = computed(() => {
|
||||
.bias-control {
|
||||
position: absolute;
|
||||
bottom: -30px;
|
||||
background: white;
|
||||
color: #333;
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-1);
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
font-size: 0.7rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -230,21 +231,21 @@ const output = computed(() => {
|
||||
}
|
||||
.bias-input {
|
||||
width: 30px;
|
||||
border: 1px solid #cbd5e1;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 2px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.formula-bar {
|
||||
margin-top: 2rem;
|
||||
background: #f8fafc;
|
||||
background: var(--vp-c-bg);
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
font-family: monospace;
|
||||
font-family: var(--vp-font-family-mono);
|
||||
font-size: 0.8rem;
|
||||
color: #334155;
|
||||
color: var(--vp-c-text-1);
|
||||
text-align: center;
|
||||
border: 1px dashed #cbd5e1;
|
||||
border: 1px dashed var(--vp-c-divider);
|
||||
}
|
||||
|
||||
input[type='range'] {
|
||||
|
||||
@@ -159,19 +159,20 @@ const mlResult = computed(() => {
|
||||
}
|
||||
|
||||
.code-block {
|
||||
background: #1e1e2e;
|
||||
color: #a6accd;
|
||||
background: var(--vp-c-bg-alt);
|
||||
color: var(--vp-c-text-1);
|
||||
padding: 0.8rem;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-family: var(--vp-font-family-mono);
|
||||
font-size: 0.8rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.mini-input {
|
||||
width: 40px;
|
||||
background: #334155;
|
||||
border: 1px solid #475569;
|
||||
color: white;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
color: var(--vp-c-text-1);
|
||||
border-radius: 2px;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -194,18 +195,18 @@ const mlResult = computed(() => {
|
||||
font-size: 1.1rem;
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
background: white;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
.result-box.big {
|
||||
color: #ef4444;
|
||||
border-color: #fecaca;
|
||||
background: #fef2f2;
|
||||
color: var(--vp-c-red-1, #ef4444);
|
||||
border-color: rgba(var(--vp-c-brand-rgb), 0.18);
|
||||
background: var(--vp-c-bg);
|
||||
}
|
||||
.result-box.small {
|
||||
color: #db2777;
|
||||
border-color: #fce7f3;
|
||||
background: #fdf2f8;
|
||||
color: var(--vp-c-text-1);
|
||||
border-color: rgba(var(--vp-c-brand-rgb), 0.18);
|
||||
background: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.note {
|
||||
@@ -224,24 +225,28 @@ const mlResult = computed(() => {
|
||||
}
|
||||
|
||||
.data-point {
|
||||
background: #e2e8f0;
|
||||
background: var(--vp-c-bg-alt);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.7rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.train-btn {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
border: none;
|
||||
background: var(--vp-c-brand);
|
||||
color: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-brand);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.train-btn:disabled {
|
||||
background: #10b981;
|
||||
cursor: default;
|
||||
background: var(--vp-c-bg);
|
||||
border-color: var(--vp-c-divider);
|
||||
color: var(--vp-c-text-2);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user