feat(docs): add NavGrid/NavCard components and restructure stage pages

- Add NavGrid.vue and NavCard.vue components for better navigation layout
- Restructure stage-0 index pages across languages into intro.md with new navigation components
- Remove old stage-0 index.md files and update stage-3 pages similarly
- Add new dependencies 'claude' and 'codex' to package.json
- Improve code formatting in multiple Vue components for better readability
- Update documentation content and structure for better user experience
This commit is contained in:
sanbuphy
2026-02-01 23:42:12 +08:00
parent a9a5c5c8a7
commit ad95658a11
171 changed files with 16366 additions and 7946 deletions
@@ -1,307 +1,507 @@
<template>
<div class="ai-evolution-demo">
<div class="header">
<div class="title">AI 进化规则 学习 生成</div>
<div class="subtitle">
点击切换阶段不自动推进避免点一下就连续发生很多事的误解
</div>
</div>
<div class="tabs" role="tablist" aria-label="AI Evolution Stages">
<button
v-for="(stage, index) in stages"
:key="stage.key"
class="tab"
:class="{ active: currentStage === index }"
role="tab"
:aria-selected="currentStage === index"
@click="currentStage = index"
>
<div class="tab-year">{{ stage.year }}</div>
<div class="tab-label">{{ stage.label }}</div>
</button>
</div>
<div class="stage">
<div class="stage-head">
<div class="stage-title">{{ stages[currentStage].title }}</div>
<div class="stage-desc">{{ stages[currentStage].desc }}</div>
</div>
<div class="grid">
<div class="card">
<div class="card-title">核心思想</div>
<ul class="list">
<li v-for="(item, i) in stages[currentStage].core" :key="i">
{{ item }}
</li>
</ul>
</div>
<div class="card">
<div class="card-title">代表应用</div>
<div class="pill-row">
<span
v-for="(tag, i) in stages[currentStage].examples"
:key="i"
class="pill"
>{{ tag }}</span
>
<div class="evolution-demo">
<el-card class="main-card" shadow="hover">
<template #header>
<div class="header-container">
<div class="title-area">
<span class="main-title">AI 进化模拟器</span>
</div>
<div class="note">{{ stages[currentStage].appDesc }}</div>
<el-steps :active="currentStage" finish-status="success" align-center class="compact-steps" simple>
<el-step v-for="stage in stages" :key="stage.id" :title="stage.label" />
</el-steps>
</div>
</template>
<div class="card full">
<div class="card-title">优势 / 局限</div>
<div class="two-col">
<div class="col">
<div class="col-title">优势</div>
<ul class="list">
<li v-for="(item, i) in stages[currentStage].pros" :key="i">
{{ item }}
</li>
</ul>
<!-- Stage 1: Rule Based (Traffic Light Example) -->
<div v-if="currentStage === 0" class="stage-pane">
<el-alert type="info" :closable="false" show-icon class="compact-alert mb-2">
<template #title><span class="alert-title">阶段一规则时代 (Rule-Based)</span></template>
<template #default><span class="alert-desc">就像教小孩如果看到红灯就停下</span></template>
</el-alert>
<div class="game-area-grid">
<div class="panel left-panel">
<div class="panel-header">规则库 (Code)</div>
<div class="code-block">
<div class="code-line">
<span class="keyword">function</span> <span class="function">decideTrafficLight</span>(color) {
</div>
<div class="code-line indent">
<span class="keyword">if</span> (color === <span class="string">'red'</span>) <span class="keyword">return</span> <span class="string">'stop'</span>
</div>
<div class="code-line indent">
<span class="keyword">else if</span> (color === <span class="string">'yellow'</span>) <span class="keyword">return</span> <span class="string">'caution'</span>
</div>
<div class="code-line indent">
<span class="keyword">else if</span> (color === <span class="string">'green'</span>) <span class="keyword">return</span> <span class="string">'go'</span>
</div>
<div class="code-line">}</div>
</div>
<div class="col">
<div class="col-title">局限</div>
<ul class="list">
<li v-for="(item, i) in stages[currentStage].cons" :key="i">
{{ item }}
</li>
</ul>
</div>
<div class="panel right-panel">
<div class="panel-header">测试输入</div>
<div class="input-controls">
<el-select v-model="ruleColor" size="small" style="width: 120px;">
<el-option value="red" label="🔴 红灯" />
<el-option value="yellow" label="🟡 黄灯" />
<el-option value="green" label="🟢 绿灯" />
<el-option value="blue" label="🔵 蓝灯" />
</el-select>
<div class="arrow"></div>
<el-tag :type="ruleResult === 'stop' ? 'danger' : ruleResult === 'caution' ? 'warning' : ruleResult === 'go' ? 'success' : 'info'">
{{ ruleResult }}
</el-tag>
</div>
<div class="hint-text" v-if="ruleResult === 'Unknown'">
规则库中没有定义"蓝灯"所以系统不知道该做什么这就是规则系统的局限性无法处理未定义的规则
</div>
<div class="hint-text" v-else>
系统严格按照预定义的规则执行指令
</div>
</div>
</div>
</div>
</div>
<!-- Stage 2: Machine Learning (Interactive 2D Plot) -->
<div v-else-if="currentStage === 1" class="stage-pane">
<el-alert type="info" :closable="false" show-icon class="compact-alert mb-2">
<template #title><span class="alert-title">阶段二机器学习 (Machine Learning)</span></template>
<template #default><span class="alert-desc">点击画布添加数据点训练模型自动寻找分类边界 (Decision Boundary)</span></template>
</el-alert>
<div class="game-area-grid">
<div class="panel left-panel canvas-container" @click="addPoint">
<!-- Simple SVG Plot -->
<svg width="100%" height="200" class="ml-plot">
<!-- Background Regions (Visible after training) -->
<rect v-if="modelTrained" x="0" y="0" width="100%" height="100%" :fill="boundaryColor" />
<!-- Decision Line -->
<line v-if="modelTrained" :x1="line.x1" :y1="line.y1" :x2="line.x2" :y2="line.y2" stroke="#333" stroke-width="2" stroke-dasharray="4" />
<!-- Points -->
<circle
v-for="(p, i) in points"
:key="i"
:cx="p.x"
:cy="p.y"
r="6"
:fill="p.type === 'A' ? '#409eff' : '#e6a23c'"
stroke="white"
stroke-width="2"
/>
</svg>
<div class="canvas-hint" v-if="points.length === 0">👆 点击此处添加数据点</div>
</div>
<div class="panel right-panel">
<div class="panel-header">控制面板</div>
<div class="control-group">
<span class="label">当前类别:</span>
<el-radio-group v-model="currentClass" size="small">
<el-radio-button label="A"><span style="color: #409eff"> 蓝类</span></el-radio-button>
<el-radio-button label="B"><span style="color: #e6a23c"> 橙类</span></el-radio-button>
</el-radio-group>
</div>
<div class="control-group mt-2">
<el-button type="primary" size="small" @click="trainLinearModel" :disabled="points.length < 2">
开始训练 (Fit)
</el-button>
<el-button size="small" :icon="Delete" circle @click="clearPoints" />
</div>
<div class="stats-info mt-2">
<p v-if="!modelTrained" class="text-desc">机器学习不再依赖硬编码规则而是通过统计学方法如寻找中心点或线性回归在数据之间划出一条"界线"试试在不同位置添加点看看界线如何变化</p>
<p v-else class="text-desc">模型已训练它找到了一条最佳分割线新进来的数据将根据它在红区还是蓝区被自动分类</p>
</div>
</div>
</div>
</div>
<!-- Stage 3: Deep Learning (3x3 Grid Feature Extraction) -->
<div v-else class="stage-pane">
<el-alert type="info" :closable="false" show-icon class="compact-alert mb-2">
<template #title><span class="alert-title">阶段三深度学习 (Deep Learning)</span></template>
<template #default><span class="alert-desc">神经网络通过多层结构自动提取特征Feature Extraction点击格子绘制图案</span></template>
</el-alert>
<div class="game-area-grid">
<div class="panel left-panel grid-container">
<div class="pixel-grid">
<div
v-for="(pixel, i) in pixels"
:key="i"
class="pixel"
:class="{ active: pixel }"
@click="togglePixel(i)"
></div>
</div>
<div class="grid-actions">
<el-button size="small" link @click="preset('x')"> X型</el-button>
<el-button size="small" link @click="preset('plus')"> 十字</el-button>
<el-button size="small" link @click="clearPixels">清空</el-button>
</div>
</div>
<div class="panel right-panel">
<div class="panel-header">神经网络层级透视</div>
<!-- Visualization of Layers -->
<div class="network-viz">
<div class="layer input-layer">
<div class="layer-label">输入层 (Pixels)</div>
<div class="nodes">
<span v-for="n in 9" :key="n" class="node mini" :class="{active: pixels[n-1]}"></span>
</div>
</div>
<div class="arrow-down"> 卷积/提取特征</div>
<div class="layer hidden-layer">
<div class="layer-label">隐藏层 (Features)</div>
<div class="feature-detectors">
<div class="feature" :class="{detected: features.center}">
<span class="f-icon"></span> 中心点
</div>
<div class="feature" :class="{detected: features.corners}">
<span class="f-icon">Corners</span> 四角
</div>
<div class="feature" :class="{detected: features.cross}">
<span class="f-icon"></span> 交叉
</div>
</div>
</div>
<div class="arrow-down"> 输出层</div>
<div class="layer output-layer">
<div class="prediction-box">
识别结果: <span class="result-text">{{ prediction }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Footer Navigation -->
<div class="footer-nav mt-2 flex justify-end">
<el-button-group>
<el-button size="small" :disabled="currentStage === 0" @click="currentStage--">上一步</el-button>
<el-button size="small" type="primary" :disabled="currentStage === 2" @click="currentStage++">下一步</el-button>
</el-button-group>
</div>
</el-card>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { ref, reactive, computed } from 'vue'
import { Delete } from '@element-plus/icons-vue'
const currentStage = ref(0)
const stages = [
{
key: 'symbolic',
year: '1950s1980s',
label: '符号主义',
title: '规则与逻辑推理(专家系统)',
desc: '相信“智能 = 规则 + 推理”。把专家经验写成 If/Then 规则与知识库。',
core: [
'知识用“符号/规则”表达:If 条件 Then 结论',
'推理引擎按规则匹配、触发、推导',
'可解释:能指出用了哪条规则'
],
pros: ['可解释性强', '在边界明确的垂直领域有效'],
cons: [
'规则写不完(组合爆炸)',
'脆弱:世界稍变就失效',
'难处理不确定性与常识'
],
examples: ['专家系统', 'MYCIN', '逻辑推理'],
appDesc:
'适合“规则明确”的任务(如部分诊断流程、合规校验),但遇到现实世界的灰度与噪声会迅速失效。'
},
{
key: 'dl',
year: '2010s',
label: '深度学习',
title: '从数据中学习(连接主义)',
desc: '相信“智能 = 表示学习 + 统计优化”。用神经网络从大量数据里自动学特征与决策边界。',
core: [
'用参数(权重)表示知识;通过优化让参数拟合数据',
'特征提取从“手写规则”变成“自动学习”',
'数据、算力、算法(GPU + 大数据 + 网络结构)共同推动'
],
pros: ['强大的模式识别能力', '同一范式覆盖多任务(视觉/语音/推荐等)'],
cons: ['数据需求大', '可解释性较弱', '对分布外/对抗样本敏感'],
examples: ['AlexNet', 'ImageNet', 'AlphaGo'],
appDesc:
'擅长“感知类”任务(图像、语音、推荐);但对“为何这么判”解释不够直观,且对数据分布较敏感。'
},
{
key: 'genai',
year: '2020s+',
label: '生成式 AI',
title: '从“分类”到“生成”(大模型)',
desc: '用 Transformer 建模上下文关系,学习“下一 token”分布,从而能生成文本/代码/图像等新内容。',
core: [
'统一接口:给提示词(prompt)→ 生成输出',
'能力来源:规模化预训练 + 指令微调/对齐',
'把很多任务“变成一个生成问题”'
],
pros: ['通用性强(多任务)', '交互友好(自然语言接口)'],
cons: [
'可能幻觉',
'安全与权限边界复杂',
'需要系统化评测与约束(格式/工具/检索)'
],
examples: ['ChatGPT', 'GPT-4', 'Midjourney'],
appDesc:
'更像“通用助手”:能写、能改、能解释、能生成;但要通过提示词、上下文与工具链把它约束到可验收、可控。'
}
{ id: 0, label: '规则', desc: '人工规则' },
{ id: 1, label: '机器学习', desc: '统计特征' },
{ id: 2, label: '深度学习', desc: '自动特征' }
]
// --- Stage 1: Rule Based ---
const ruleColor = ref('red')
const ruleResult = computed(() => {
if (ruleColor.value === 'red') return 'stop'
if (ruleColor.value === 'yellow') return 'caution'
if (ruleColor.value === 'green') return 'go'
return 'Unknown'
})
// --- Stage 2: Machine Learning ---
const points = ref([])
const currentClass = ref('A')
const modelTrained = ref(false)
const line = reactive({ x1: 0, y1: 0, x2: 0, y2: 0 })
// SVG click coordinates are relative to the SVG element
// We'll use a simple approximation for the demo
// x, y are percentages (0-100)
const addPoint = (e) => {
const rect = e.target.getBoundingClientRect()
// Ensure we are clicking on the SVG or its children
// Best to put event on wrapper
// But event target might be circle.
// Use currentTarget
const x = e.offsetX
const y = e.offsetY
// Convert to % for responsiveness if needed, but pixel is easier for calc
// Let's stick to pixel for this simple demo, assuming fixed height 200
// width varies.
points.value.push({
x, y,
type: currentClass.value
})
modelTrained.value = false
}
const clearPoints = () => {
points.value = []
modelTrained.value = false
}
const trainLinearModel = () => {
// Simple Nearest Centroid Classifier
const groupA = points.value.filter(p => p.type === 'A')
const groupB = points.value.filter(p => p.type === 'B')
if (groupA.length === 0 || groupB.length === 0) return
const avgA = {
x: groupA.reduce((sum, p) => sum + p.x, 0) / groupA.length,
y: groupA.reduce((sum, p) => sum + p.y, 0) / groupA.length
}
const avgB = {
x: groupB.reduce((sum, p) => sum + p.x, 0) / groupB.length,
y: groupB.reduce((sum, p) => sum + p.y, 0) / groupB.length
}
// Midpoint
const midX = (avgA.x + avgB.x) / 2
const midY = (avgA.y + avgB.y) / 2
// Normal vector (from A to B)
const dx = avgB.x - avgA.x
const dy = avgB.y - avgA.y
// Perpendicular line: dx*x + dy*y = C
// Slope of normal is dy/dx. Slope of perp line is -dx/dy
// Let's just draw a line perpendicular to the segment AB passing through Midpoint
// Slope m = -dx/dy
// Calculate line coordinates for visualization
// y - midY = m * (x - midX)
// if dy is close to 0, vertical line x = midX
const width = 1000 // ample width
if (Math.abs(dy) < 0.001) {
// Vertical line
line.x1 = midX
line.x2 = midX
line.y1 = 0
line.y2 = 200
} else {
const m = -dx / dy
// At x=0
const y0 = midY + m * (0 - midX)
// At x=width
const y1 = midY + m * (width - midX)
line.x1 = 0
line.y1 = y0
line.x2 = width
line.y2 = y1
}
modelTrained.value = true
}
// Simple visual background
// If A is left/top, background is blue-ish
// SVG doesn't support "half plane fill" easily without path math
// For this demo, we won't fill the background perfectly, just draw the line.
const boundaryColor = computed(() => 'transparent')
// --- Stage 3: Deep Learning ---
const pixels = ref(Array(9).fill(false))
const togglePixel = (index) => {
pixels.value[index] = !pixels.value[index]
}
const clearPixels = () => {
pixels.value = pixels.value.map(() => false)
}
const preset = (type) => {
clearPixels()
if (type === 'x') {
[0, 2, 4, 6, 8].forEach(i => pixels.value[i] = true)
} else if (type === 'plus') {
[1, 3, 4, 5, 7].forEach(i => pixels.value[i] = true)
}
}
const features = computed(() => {
// Simple heuristics to simulate feature detection
const p = pixels.value
const center = p[4]
const corners = p[0] && p[2] && p[6] && p[8]
const cross = p[1] && p[3] && p[5] && p[7]
return { center, corners, cross }
})
const prediction = computed(() => {
const f = features.value
if (f.corners && f.center) return 'X 型图案 (X-Shape)'
if (f.cross && f.center) return '十字型 (Plus-Shape)'
if (f.corners && !f.center) return '四角 (Corners)'
if (pixels.value.filter(Boolean).length === 0) return '无输入'
return '未知图案'
})
</script>
<style scoped>
.ai-evolution-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 8px;
padding: 1.5rem;
margin: 1rem 0;
color: var(--vp-c-text-1);
}
.evolution-demo { margin: 10px 0; }
.header-container { margin-bottom: 5px; }
.main-title { font-weight: bold; font-size: 16px; }
.compact-steps { padding: 5px 0; margin-bottom: 10px; }
.compact-alert { padding: 5px 10px; }
.alert-title { font-weight: bold; font-size: 13px; }
.alert-desc { font-size: 12px; }
.header {
margin-bottom: 1rem;
}
.title {
font-weight: 800;
color: var(--vp-c-text-1);
}
.subtitle {
margin-top: 0.25rem;
color: var(--vp-c-text-2);
font-size: 0.9rem;
}
.tabs {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.5rem;
margin: 0.75rem 0 1rem;
}
.tab {
text-align: left;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg);
color: var(--vp-c-text-1);
border-radius: 8px;
padding: 0.6rem 0.75rem;
cursor: pointer;
transition:
border-color 0.2s ease,
box-shadow 0.2s ease;
}
.tab:hover {
border-color: rgba(var(--vp-c-brand-rgb), 0.55);
}
.tab.active {
border-color: var(--vp-c-brand);
box-shadow: 0 0 0 3px rgba(var(--vp-c-brand-rgb), 0.12);
}
.tab-year {
font-size: 0.75rem;
color: var(--vp-c-text-2);
font-family: var(--vp-font-family-mono);
}
.tab-label {
margin-top: 0.15rem;
font-weight: 800;
}
.stage-head {
margin-bottom: 0.75rem;
}
.stage-title {
font-weight: 900;
color: var(--vp-c-text-1);
}
.stage-desc {
margin-top: 0.25rem;
color: var(--vp-c-text-2);
font-size: 0.95rem;
line-height: 1.6;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.75rem;
}
@media (max-width: 720px) {
.tabs {
grid-template-columns: 1fr;
}
.grid {
grid-template-columns: 1fr;
}
}
.card {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg);
border-radius: 8px;
padding: 1rem;
}
.card.full {
grid-column: 1 / -1;
}
.card-title {
font-weight: 900;
color: var(--vp-c-text-1);
margin-bottom: 0.5rem;
}
.list {
margin: 0;
padding-left: 1.15rem;
color: var(--vp-c-text-1);
}
.pill-row {
.game-area-grid {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 0.5rem;
gap: 15px;
margin-top: 10px;
}
.panel {
border: 1px solid #ebeef5;
border-radius: 4px;
padding: 10px;
}
.left-panel { flex: 1; }
.right-panel { flex: 1; background-color: #fcfcfc; }
.panel-header {
font-size: 13px;
font-weight: bold;
color: #606266;
margin-bottom: 10px;
border-bottom: 1px solid #ebeef5;
padding-bottom: 5px;
}
.pill {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-alt);
color: var(--vp-c-text-2);
padding: 0.2rem 0.6rem;
border-radius: 999px;
font-size: 0.8rem;
font-weight: 700;
/* Stage 1 */
.code-block {
font-family: monospace;
font-size: 12px;
background: #282c34;
color: #abb2bf;
padding: 10px;
border-radius: 4px;
}
.keyword { color: #c678dd; }
.string { color: #98c379; }
.function { color: #61afef; }
.indent { padding-left: 15px; }
.input-controls {
display: flex;
align-items: center;
gap: 10px;
}
.hint-text {
margin-top: 10px;
font-size: 12px;
color: #909399;
}
.note {
color: var(--vp-c-text-2);
line-height: 1.6;
/* Stage 2 */
.canvas-container {
height: 220px;
background-color: #f5f7fa;
position: relative;
cursor: crosshair;
padding: 0;
overflow: hidden;
}
.ml-plot {
display: block;
}
.canvas-hint {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #909399;
font-size: 12px;
pointer-events: none;
}
.text-desc {
font-size: 12px;
color: #606266;
line-height: 1.5;
}
.two-col {
/* Stage 3 */
.grid-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.pixel-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.75rem;
grid-template-columns: repeat(3, 40px);
gap: 4px;
margin-bottom: 10px;
}
.pixel {
width: 40px;
height: 40px;
background-color: #eee;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s;
}
.pixel:hover { background-color: #d9d9d9; }
.pixel.active { background-color: #333; }
@media (max-width: 720px) {
.two-col {
grid-template-columns: 1fr;
}
.network-viz {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.layer {
width: 100%;
padding: 5px;
background: #fff;
border: 1px solid #ebeef5;
border-radius: 4px;
text-align: center;
}
.layer-label { font-size: 11px; color: #909399; margin-bottom: 4px; }
.nodes { display: flex; gap: 2px; justify-content: center; flex-wrap: wrap; width: 60px; margin: 0 auto; }
.node.mini { width: 6px; height: 6px; border-radius: 50%; background: #ddd; }
.node.mini.active { background: #333; }
.arrow-down { font-size: 10px; color: #ccc; }
.col-title {
font-weight: 900;
color: var(--vp-c-text-1);
margin-bottom: 0.35rem;
.feature-detectors {
display: flex;
justify-content: space-around;
font-size: 11px;
}
</style>
.feature {
display: flex;
flex-direction: column;
align-items: center;
opacity: 0.3;
transition: opacity 0.3s;
}
.feature.detected { opacity: 1; color: #409eff; font-weight: bold; }
.f-icon { font-size: 14px; margin-bottom: 2px; }
.prediction-box { font-weight: bold; font-size: 13px; color: #303133; }
.result-text { color: #67c23a; }
@media (max-width: 600px) {
.game-area-grid { flex-direction: column; }
}
.flex { display: flex; }
.justify-end { justify-content: flex-end; }
.mt-2 { margin-top: 8px; }
.mb-2 { margin-bottom: 8px; }
</style>