feat(i18n): add AI history components internationalization support
- Add useI18n composable and ai-history locale files - Refactor 10 AI history Vue components to support i18n (GPTEvolutionDemo, AIErasComparisonDemo, AiEvolutionDemo, etc.) - Add English version of AI history appendix article - Add English translations for stage-1 appendix-articles: - vibe-coding-tools-snake-game-tutorial.md - vibe-coding-tools-build-website-with-ai-coding-and-design-agents.md - Use relative paths to reference Chinese version images - Update appendix sidebar config to use English AI history link
This commit is contained in:
@@ -2,28 +2,28 @@
|
||||
<div class="demo-card">
|
||||
<div class="era-container">
|
||||
<div class="era-header">
|
||||
🌟 AI 发展阶段与核心范式全景对比
|
||||
{{ t('erasComparison.header') }}
|
||||
</div>
|
||||
<div class="era-grid">
|
||||
<div v-for="era in eras" :key="era.name" class="era-item" :style="{ borderTopColor: era.color }">
|
||||
<div class="e-icon" :style="{ background: era.color }">{{ era.icon }}</div>
|
||||
<div class="e-name" :style="{ color: era.color }">{{ era.name }}</div>
|
||||
<div v-for="(era, i) in localEras" :key="i" class="era-item" :style="{ borderTopColor: eraStyles[i]?.color }">
|
||||
<div class="e-icon" :style="{ background: eraStyles[i]?.color }">{{ eraStyles[i]?.icon }}</div>
|
||||
<div class="e-name" :style="{ color: eraStyles[i]?.color }">{{ era.name }}</div>
|
||||
<div class="e-time">{{ era.time }}</div>
|
||||
|
||||
|
||||
<div class="e-section">
|
||||
<div class="e-label">驱动方式</div>
|
||||
<div class="e-label">{{ t('erasComparison.driverLabel') }}</div>
|
||||
<div class="e-value">{{ era.driver }}</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="e-section">
|
||||
<div class="e-label">核心机制</div>
|
||||
<div class="e-label">{{ t('erasComparison.mechanismLabel') }}</div>
|
||||
<div class="e-value">
|
||||
<span class="highlight">{{ era.mechanism }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="e-section">
|
||||
<div class="e-label">典型代表</div>
|
||||
<div class="e-label">{{ t('erasComparison.examplesLabel') }}</div>
|
||||
<div class="e-tags">
|
||||
<span v-for="tag in era.examples" :key="tag" class="e-tag">{{ tag }}</span>
|
||||
</div>
|
||||
@@ -35,52 +35,19 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const eras = [
|
||||
{
|
||||
name: '规则系统时代',
|
||||
time: '1960s - 1980s',
|
||||
icon: '📜',
|
||||
color: '#059669', // emerald
|
||||
driver: '人类硬编码知识',
|
||||
mechanism: 'If-Then 逻辑推演',
|
||||
examples: ['Dendral', '深蓝 (Deep Blue)']
|
||||
},
|
||||
{
|
||||
name: '传统机器学习',
|
||||
time: '1990s - 2000s',
|
||||
icon: '📊',
|
||||
color: '#d97706', // amber
|
||||
driver: '人工特征工程 + 统计学',
|
||||
mechanism: '寻找数学决策边界',
|
||||
examples: ['支持向量机 (SVM)', '随机森林']
|
||||
},
|
||||
{
|
||||
name: '深度学习革命',
|
||||
time: '2010s',
|
||||
icon: '🧠',
|
||||
color: '#dc2626', // red
|
||||
driver: '大数据 + 算力爬升',
|
||||
mechanism: '神经网络自动提取特征',
|
||||
examples: ['AlexNet (CNN)', 'AlphaGo (RL)']
|
||||
},
|
||||
{
|
||||
name: '大语言模型 (LLM)',
|
||||
time: '2018 - 至今',
|
||||
icon: '💬',
|
||||
color: '#7c3aed', // violet
|
||||
driver: '海量无标注数据 + 暴力计算',
|
||||
mechanism: '预测下一个词 + 涌现常识',
|
||||
examples: ['GPT-4', 'Claude 3']
|
||||
},
|
||||
{
|
||||
name: '智能体 (Agentic AI)',
|
||||
time: '现在 - 未来',
|
||||
icon: '🤖',
|
||||
color: '#0284c7', // light blue
|
||||
driver: '大模型大脑 + 环境感知',
|
||||
mechanism: '自主规划 + 工具调用',
|
||||
examples: ['AI 程序员', '具身智能']
|
||||
}
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from '../../../composables/useI18n.js'
|
||||
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||
|
||||
const { t, messages } = useI18n(aiHistoryLocale)
|
||||
const localEras = computed(() => messages.value.erasComparison?.eras ?? [])
|
||||
|
||||
const eraStyles = [
|
||||
{ icon: '📜', color: '#059669' },
|
||||
{ icon: '📊', color: '#d97706' },
|
||||
{ icon: '🧠', color: '#dc2626' },
|
||||
{ icon: '💬', color: '#7c3aed' },
|
||||
{ icon: '🤖', color: '#0284c7' },
|
||||
]
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,29 +1,36 @@
|
||||
<template>
|
||||
<div class="demo-card">
|
||||
<div class="timeline-visual">
|
||||
<div v-for="era in eras" :key="era.label" class="era" :style="{ flex: era.flex, background: era.bg }">
|
||||
<div class="era-label">{{ era.label }}</div>
|
||||
<div class="era-years">{{ era.years }}</div>
|
||||
<div v-for="(era, i) in eras" :key="i" class="era" :style="{ flex: era.flex, background: era.bg }">
|
||||
<div class="era-label">{{ localeEras[i]?.label ?? era.label }}</div>
|
||||
<div class="era-years">{{ localeEras[i]?.years ?? era.years }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="legend">
|
||||
<span class="legend-item"><span class="dot" style="background:#059669"></span>技术浪潮</span>
|
||||
<span class="legend-item"><span class="dot" style="background:#94a3b8"></span>❄️ AI 寒冬</span>
|
||||
<span class="legend-item"><span class="dot" style="background:#7c3aed"></span>大模型时代</span>
|
||||
<span class="legend-item"><span class="dot" style="background:#059669"></span>{{ t('aiEvolution.legend.wave') }}</span>
|
||||
<span class="legend-item"><span class="dot" style="background:#94a3b8"></span>{{ t('aiEvolution.legend.winter') }}</span>
|
||||
<span class="legend-item"><span class="dot" style="background:#7c3aed"></span>{{ t('aiEvolution.legend.llm') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from '../../../composables/useI18n.js'
|
||||
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||
|
||||
const { t, messages } = useI18n(aiHistoryLocale)
|
||||
const localeEras = computed(() => messages.value.aiEvolution?.eras ?? [])
|
||||
|
||||
const eras = [
|
||||
{ label: '理论奠基', years: '1940s-50s', flex: 1.5, bg: 'linear-gradient(135deg, #dbeafe, #bfdbfe)' },
|
||||
{ label: '第一次浪潮', years: '1960s-70s', flex: 1.5, bg: 'linear-gradient(135deg, #d1fae5, #a7f3d0)' },
|
||||
{ label: '❄️ 寒冬 I', years: '1974-80', flex: 0.7, bg: 'linear-gradient(135deg, #e2e8f0, #cbd5e1)' },
|
||||
{ label: '第二次浪潮', years: '1980s', flex: 1, bg: 'linear-gradient(135deg, #d1fae5, #a7f3d0)' },
|
||||
{ label: '❄️ 寒冬 II', years: '1987-93', flex: 0.7, bg: 'linear-gradient(135deg, #e2e8f0, #cbd5e1)' },
|
||||
{ label: 'ML 崛起', years: '1990s-2000s', flex: 1.5, bg: 'linear-gradient(135deg, #d1fae5, #6ee7b7)' },
|
||||
{ label: '深度学习', years: '2010s', flex: 1.2, bg: 'linear-gradient(135deg, #a7f3d0, #34d399)' },
|
||||
{ label: '大模型时代', years: '2018+', flex: 1.2, bg: 'linear-gradient(135deg, #c4b5fd, #a78bfa)' },
|
||||
{ flex: 1.5, bg: 'linear-gradient(135deg, #dbeafe, #bfdbfe)' },
|
||||
{ flex: 1.5, bg: 'linear-gradient(135deg, #d1fae5, #a7f3d0)' },
|
||||
{ flex: 0.7, bg: 'linear-gradient(135deg, #e2e8f0, #cbd5e1)' },
|
||||
{ flex: 1, bg: 'linear-gradient(135deg, #d1fae5, #a7f3d0)' },
|
||||
{ flex: 0.7, bg: 'linear-gradient(135deg, #e2e8f0, #cbd5e1)' },
|
||||
{ flex: 1.5, bg: 'linear-gradient(135deg, #d1fae5, #6ee7b7)' },
|
||||
{ flex: 1.2, bg: 'linear-gradient(135deg, #a7f3d0, #34d399)' },
|
||||
{ flex: 1.2, bg: 'linear-gradient(135deg, #c4b5fd, #a78bfa)' },
|
||||
]
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="demo-card">
|
||||
<div class="attention-layout">
|
||||
<div class="sentence-col">
|
||||
<div class="col-label">处理「<strong>他</strong>」时的注意力分配:</div>
|
||||
<div class="col-label" v-html="colLabel"></div>
|
||||
<div class="sentence-box">
|
||||
<span v-for="(word, i) in sentence" :key="i" class="word-token" :class="{ focus: i === focusIdx }">{{ word }}</span>
|
||||
</div>
|
||||
@@ -18,16 +18,26 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="caption">
|
||||
「他」虽在句中间,模型却把 65% 注意力精准投向句首的「小明」,跨越距离识别代词指代
|
||||
{{ t('attention.caption') }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const sentence = ['小明', '把', '苹果', '给了', '他', '的', '母亲']
|
||||
const focusIdx = 4
|
||||
const attn = [0.65, 0.05, 0.10, 0.10, 0.05, 0.03, 0.02]
|
||||
const weights = sentence.map((word, i) => ({ word, w: attn[i] }))
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from '../../../composables/useI18n.js'
|
||||
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||
|
||||
const { t, messages } = useI18n(aiHistoryLocale)
|
||||
|
||||
const attnData = computed(() => messages.value.attention ?? {})
|
||||
const sentence = computed(() => attnData.value.sentence ?? [])
|
||||
const focusIdx = computed(() => attnData.value.focusIdx ?? 4)
|
||||
const rawWeights = computed(() => attnData.value.weights ?? [])
|
||||
const weights = computed(() => sentence.value.map((word, i) => ({ word, w: rawWeights.value[i] ?? 0 })))
|
||||
const focusWord = computed(() => sentence.value[focusIdx.value] ?? '')
|
||||
const colLabel = computed(() => (attnData.value.colLabel ?? '').replace('{word}', focusWord.value))
|
||||
|
||||
const barColor = (v) => v > 0.5 ? '#dc2626' : v > 0.15 ? '#d97706' : v > 0.06 ? '#059669' : 'var(--vp-c-divider)'
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="demo-card">
|
||||
<div class="bp-flow">
|
||||
<div v-for="(step, i) in steps" :key="i" class="step-block" :style="{ borderTopColor: step.color }">
|
||||
<div class="step-num" :style="{ background: step.color }">{{ i + 1 }}</div>
|
||||
<div v-for="(step, i) in localSteps" :key="i" class="step-block" :style="{ borderTopColor: stepColors[i] }">
|
||||
<div class="step-num" :style="{ background: stepColors[i] }">{{ i + 1 }}</div>
|
||||
<div class="step-icon">{{ step.icon }}</div>
|
||||
<div class="step-name">{{ step.name }}</div>
|
||||
<div class="step-desc">{{ step.desc }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loss-visual">
|
||||
<div class="loss-label">Loss(误差)随训练轮次下降:</div>
|
||||
<div class="loss-label">{{ t('backprop.lossLabel') }}</div>
|
||||
<svg viewBox="0 0 320 130" class="loss-svg">
|
||||
<!-- Axes -->
|
||||
<line x1="40" y1="110" x2="300" y2="110" stroke="var(--vp-c-text-3)" stroke-width="1.5" />
|
||||
@@ -21,12 +21,12 @@
|
||||
<polygon points="37,15 40,10 43,15" fill="var(--vp-c-text-3)" />
|
||||
|
||||
<!-- Y Label -->
|
||||
<text x="30" y="25" text-anchor="end" class="ax-text">高</text>
|
||||
<text x="30" y="105" text-anchor="end" class="ax-text">低</text>
|
||||
<text x="30" y="25" text-anchor="end" class="ax-text">{{ t('backprop.axisHigh') }}</text>
|
||||
<text x="30" y="105" text-anchor="end" class="ax-text">{{ t('backprop.axisLow') }}</text>
|
||||
<text x="20" y="65" text-anchor="middle" transform="rotate(-90 20 65)" class="ax-title">Loss</text>
|
||||
|
||||
<!-- X Label -->
|
||||
<text x="300" y="125" text-anchor="end" class="ax-title">训练轮次 (Epochs)</text>
|
||||
<text x="300" y="125" text-anchor="end" class="ax-title">{{ t('backprop.axisEpochs') }}</text>
|
||||
|
||||
<!-- Loss 曲线 -->
|
||||
<polyline :points="lossPoints" fill="none" stroke="var(--vp-c-brand)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
@@ -36,12 +36,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const steps = [
|
||||
{ icon: '➡️', name: '前向传播', desc: '数据流过网络,得出预测', color: '#3b82f6' },
|
||||
{ icon: '📐', name: '计算误差', desc: '预测值 vs 正确答案,算 Loss', color: '#d97706' },
|
||||
{ icon: '⬅️', name: '反向传播', desc: '逐层追溯每个权重的"责任"', color: '#dc2626' },
|
||||
{ icon: '⚙️', name: '更新权重', desc: '按责任微调,减少下次误差', color: '#059669' },
|
||||
]
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from '../../../composables/useI18n.js'
|
||||
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||
|
||||
const { t, messages } = useI18n(aiHistoryLocale)
|
||||
const localSteps = computed(() => messages.value.backprop?.steps ?? [])
|
||||
|
||||
const stepColors = ['#3b82f6', '#d97706', '#dc2626', '#059669']
|
||||
const lossPoints = (() => {
|
||||
const pts = []
|
||||
for (let i = 0; i <= 50; i++) {
|
||||
|
||||
+16
-9
@@ -1,24 +1,31 @@
|
||||
<template>
|
||||
<div class="demo-card">
|
||||
<div class="schools-grid">
|
||||
<div v-for="s in schools" :key="s.name" class="school-card" :style="{ borderTopColor: s.color }">
|
||||
<div v-for="(s, i) in schoolStyles" :key="i" class="school-card" :style="{ borderTopColor: s.color }">
|
||||
<div class="card-head">
|
||||
<span class="school-icon">{{ s.icon }}</span>
|
||||
<span class="school-name" :style="{ color: s.color }">{{ s.name }}</span>
|
||||
<span class="school-name" :style="{ color: s.color }">{{ localeItems[i]?.name }}</span>
|
||||
</div>
|
||||
<div class="school-idea">{{ s.idea }}</div>
|
||||
<div class="school-rep">代表:{{ s.rep }}</div>
|
||||
<div class="school-status">{{ s.status }}</div>
|
||||
<div class="school-idea">{{ localeItems[i]?.idea }}</div>
|
||||
<div class="school-rep">{{ t('schools.repLabel') }}:{{ localeItems[i]?.rep }}</div>
|
||||
<div class="school-status">{{ localeItems[i]?.status }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const schools = [
|
||||
{ name: '符号主义', icon: '📜', color: '#059669', idea: '智能 = 符号推理 / If-Then 规则', rep: '专家系统、深蓝', status: '→ 与连接主义融合(神经符号 AI)' },
|
||||
{ name: '连接主义', icon: '🧠', color: '#7c3aed', idea: '智能 = 神经元网络 + 海量数据', rep: 'AlphaGo、GPT 系列', status: '→ 主导大模型时代,当前主流' },
|
||||
{ name: '行为主义', icon: '🎮', color: '#d97706', idea: '智能 = 与环境互动 / 强化学习', rep: 'AlphaGo(RL 部分)', status: '→ 与连接主义融合(深度强化学习)' },
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from '../../../composables/useI18n.js'
|
||||
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||
|
||||
const { t, messages } = useI18n(aiHistoryLocale)
|
||||
const localeItems = computed(() => messages.value.schools?.items ?? [])
|
||||
|
||||
const schoolStyles = [
|
||||
{ icon: '📜', color: '#059669' },
|
||||
{ icon: '🧠', color: '#7c3aed' },
|
||||
{ icon: '🎮', color: '#d97706' },
|
||||
]
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
<template>
|
||||
<div class="demo-card">
|
||||
<div class="demo-label">符号主义的核心思路 ── 把知识写成规则</div>
|
||||
<div class="demo-label">{{ t('foundation.label') }}</div>
|
||||
<div class="code-block">
|
||||
<div class="code-line"><span class="kw">IF</span> 体温 > 38.5°C <span class="kw">AND</span> 白细胞计数 > 11000</div>
|
||||
<div class="code-line indent"><span class="kw">THEN</span> 诊断 = <span class="str">"细菌感染"</span></div>
|
||||
<div class="code-line"><span class="kw">IF</span> 诊断 = <span class="str">"细菌感染"</span> <span class="kw">AND</span> 对青霉素不过敏</div>
|
||||
<div class="code-line indent"><span class="kw">THEN</span> 治疗方案 = <span class="str">"青霉素 400mg / 每日两次"</span></div>
|
||||
<div class="code-line comment">// 早期医疗专家系统(MYCIN,1977)就是由 450+ 条这样的规则组成的</div>
|
||||
<div v-for="(line, i) in foundationLines" :key="i" class="code-line" :class="{ indent: line.indent }">
|
||||
<template v-for="(p, j) in line.parts" :key="j">
|
||||
<span v-if="p.kw" class="kw">{{ p.kw }}</span>
|
||||
<span v-else-if="p.str" class="str">{{ p.str }}</span>
|
||||
<template v-else>{{ p.text }}</template>
|
||||
</template>
|
||||
</div>
|
||||
<div class="code-line comment">{{ t('foundation.comment') }}</div>
|
||||
</div>
|
||||
<div class="demo-caption">人类专家把经验翻译成一条条 IF-THEN 规则,机器逐条匹配执行</div>
|
||||
<div class="demo-caption">{{ t('foundation.caption') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from '../../../composables/useI18n.js'
|
||||
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||
|
||||
const { t, messages } = useI18n(aiHistoryLocale)
|
||||
const foundationLines = computed(() => messages.value.foundation?.lines ?? [])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div class="demo-card">
|
||||
<div class="gpt-grid">
|
||||
<div v-for="m in models" :key="m.name" class="gpt-card" :style="{ borderTopColor: m.color }">
|
||||
<div v-for="(m, i) in models" :key="i" class="gpt-card" :style="{ borderTopColor: modelColors[i] }">
|
||||
<div class="card-top">
|
||||
<span class="gpt-name" :style="{ color: m.color }">{{ m.name }}</span>
|
||||
<span class="gpt-name" :style="{ color: modelColors[i] }">{{ m.name }}</span>
|
||||
<span class="gpt-year">{{ m.year }}</span>
|
||||
</div>
|
||||
<div class="param-val">{{ m.params }}</div>
|
||||
<div class="param-bar-bg">
|
||||
<div class="param-bar" :style="{ width: m.barWidth, background: m.color }"></div>
|
||||
<div class="param-bar" :style="{ width: m.barWidth, background: modelColors[i] }"></div>
|
||||
</div>
|
||||
<div class="gpt-key">{{ m.key }}</div>
|
||||
</div>
|
||||
@@ -17,12 +17,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const models = [
|
||||
{ name: 'GPT-1', year: '2018', params: '1.17 亿', barWidth: '2%', color: '#94a3b8', key: '预训练+微调范式确立' },
|
||||
{ name: 'GPT-2', year: '2019', params: '15 亿', barWidth: '6%', color: '#3b82f6', key: 'Zero-shot 零样本泛化' },
|
||||
{ name: 'GPT-3', year: '2020', params: '1750 亿', barWidth: '45%', color: '#7c3aed', key: '⚡ 涌现!上下文学习' },
|
||||
{ name: 'GPT-4', year: '2023', params: '~1.8 万亿', barWidth: '100%', color: '#dc2626', key: '多模态 + 复杂推理' },
|
||||
]
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from '../../../composables/useI18n.js'
|
||||
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||
|
||||
const { messages } = useI18n(aiHistoryLocale)
|
||||
const models = computed(() => messages.value.gptEvolution ?? [])
|
||||
|
||||
const modelColors = ['#94a3b8', '#3b82f6', '#7c3aed', '#dc2626']
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
+23
-17
@@ -7,12 +7,12 @@
|
||||
<g v-for="layer in layers" :key="layer.idx">
|
||||
<circle v-for="n in layer.nodes" :key="n.id" :cx="n.x" :cy="n.y" r="15" :fill="layer.fill" :stroke="layer.stroke" stroke-width="2" />
|
||||
</g>
|
||||
<text v-for="layer in layers" :key="'l-'+layer.idx" :x="layer.x" y="194" text-anchor="middle" :fill="layer.stroke" class="lbl">{{ layer.name }}</text>
|
||||
<text v-for="(layer, i) in layers" :key="'l-'+layer.idx" :x="layer.x" y="194" text-anchor="middle" :fill="layer.stroke" class="lbl">{{ localLayers[i]?.name }}</text>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="layer-cards">
|
||||
<div v-for="info in layerInfo" :key="info.name" class="layer-card" :style="{ borderLeftColor: info.color }">
|
||||
<div class="lc-title" :style="{ color: info.color }">{{ info.name }}</div>
|
||||
<div v-for="(info, i) in localLayers" :key="i" class="layer-card" :style="{ borderLeftColor: layerColors[i]?.color }">
|
||||
<div class="lc-title" :style="{ color: layerColors[i]?.color }">{{ info.name }}</div>
|
||||
<div class="lc-desc">{{ info.desc }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -21,27 +21,33 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from '../../../composables/useI18n.js'
|
||||
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||
|
||||
const { messages } = useI18n(aiHistoryLocale)
|
||||
const localLayers = computed(() => messages.value.neuralNet?.layers ?? [])
|
||||
|
||||
const W = 380, H = 185
|
||||
const layerDef = [
|
||||
{ name: '输入层', count: 3, xFrac: 0.13, color: '#3b82f6', fill: '#dbeafe' },
|
||||
{ name: '隐藏层', count: 4, xFrac: 0.5, color: '#7c3aed', fill: '#ede9fe' },
|
||||
{ name: '输出层', count: 2, xFrac: 0.87, color: '#059669', fill: '#d1fae5' },
|
||||
const layerColors = [
|
||||
{ color: '#3b82f6', fill: '#dbeafe' },
|
||||
{ color: '#7c3aed', fill: '#ede9fe' },
|
||||
{ color: '#059669', fill: '#d1fae5' },
|
||||
]
|
||||
const layers = layerDef.map((l, idx) => {
|
||||
const x = l.xFrac * W
|
||||
const gap = Math.min(46, (H - 36) / (l.count - 1 || 1))
|
||||
const startY = (H - gap * (l.count - 1)) / 2
|
||||
return { idx, x, name: l.name, fill: l.fill, stroke: l.color, nodes: Array.from({ length: l.count }, (_, i) => ({ id: `${idx}-${i}`, x, y: startY + i * gap })) }
|
||||
const layerCounts = [3, 4, 2]
|
||||
const xFracs = [0.13, 0.5, 0.87]
|
||||
|
||||
const layers = layerColors.map((l, idx) => {
|
||||
const x = xFracs[idx] * W
|
||||
const count = layerCounts[idx]
|
||||
const gap = Math.min(46, (H - 36) / (count - 1 || 1))
|
||||
const startY = (H - gap * (count - 1)) / 2
|
||||
return { idx, x, fill: l.fill, stroke: l.color, nodes: Array.from({ length: count }, (_, i) => ({ id: `${idx}-${i}`, x, y: startY + i * gap })) }
|
||||
})
|
||||
const connections = []
|
||||
for (let li = 0; li < layers.length - 1; li++) {
|
||||
layers[li].nodes.forEach(a => { layers[li + 1].nodes.forEach(b => { connections.push({ id: `${a.id}-${b.id}`, x1: a.x, y1: a.y, x2: b.x, y2: b.y }) }) })
|
||||
}
|
||||
const layerInfo = [
|
||||
{ name: '输入层', desc: '原始像素 / 数值信号', color: '#3b82f6' },
|
||||
{ name: '隐藏层(可叠加多层)', desc: '底层识别边缘 → 中层识别形状 → 高层识别语义概念', color: '#7c3aed' },
|
||||
{ name: '输出层', desc: '最终分类或预测结果', color: '#059669' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<div class="demo-card">
|
||||
<div class="perceptron-layout">
|
||||
<div class="inputs-col">
|
||||
<div v-for="inp in inputs" :key="inp.label" class="input-node">
|
||||
<div v-for="(inp, i) in inputs" :key="i" class="input-node">
|
||||
<span class="node-circle">{{ inp.val }}</span>
|
||||
<span class="node-label">{{ inp.label }}</span>
|
||||
<span class="node-label">{{ featureLabels[i] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="weights-col">
|
||||
<div v-for="inp in inputs" :key="inp.label" class="weight-arrow">
|
||||
<div v-for="(inp, i) in inputs" :key="i" class="weight-arrow">
|
||||
<span class="arrow">→</span>
|
||||
<span class="w-tag">×{{ inp.weight }}</span>
|
||||
</div>
|
||||
@@ -18,7 +18,7 @@
|
||||
<div class="n-sym">Σ</div>
|
||||
<div class="n-val">{{ sum }}</div>
|
||||
</div>
|
||||
<span class="bias-tag">偏置 {{ bias }}</span>
|
||||
<span class="bias-tag">{{ t('perceptron.biasLabel') }} {{ bias }}</span>
|
||||
</div>
|
||||
<div class="act-col">
|
||||
<span class="arrow big">→</span>
|
||||
@@ -28,19 +28,23 @@
|
||||
<div class="output-col">
|
||||
<div class="output-node" :class="{ on: output === 1 }">
|
||||
<span class="out-val">{{ output }}</span>
|
||||
<span class="out-lbl">{{ output ? '激活' : '静默' }}</span>
|
||||
<span class="out-lbl">{{ output ? t('perceptron.activated') : t('perceptron.silent') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="caption">
|
||||
① 输入特征 ② 乘以权重(重要性) ③ 求和 + 偏置 ④ 超过阈值就激活输出 1,否则输出 0
|
||||
</div>
|
||||
<div class="caption">{{ t('perceptron.caption') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
const inputs = [{ label: '特征 x₁', val: 1, weight: 0.6 }, { label: '特征 x₂', val: 0, weight: 0.4 }]
|
||||
import { useI18n } from '../../../composables/useI18n.js'
|
||||
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||
|
||||
const { t, messages } = useI18n(aiHistoryLocale)
|
||||
const featureLabels = computed(() => messages.value.perceptron?.features ?? [])
|
||||
|
||||
const inputs = [{ val: 1, weight: 0.6 }, { val: 0, weight: 0.4 }]
|
||||
const bias = -0.3
|
||||
const sum = computed(() => Number((inputs.reduce((s, i) => s + i.val * i.weight, 0) + bias).toFixed(2)))
|
||||
const output = computed(() => sum.value > 0 ? 1 : 0)
|
||||
|
||||
Reference in New Issue
Block a user