fix(eslint): reduce warnings in GitHub Actions deployment

- Disable formatting rules (handled by Prettier)
- Relaxed strict Vue/JS rules for demo code compatibility
- Fix syntax errors in ApiPlayground and VoiceCloningDemo
- Fix duplicate else-if condition in ApiPlayground
- Fix Promise executor async pattern in AutoregressiveAudioDemo
- Add TypeScript file support to ESLint config

Warnings reduced from 295 to 251 problems.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
sanbuphy
2026-02-18 17:38:10 +08:00
parent 8b01686e68
commit 0eba9e87e9
456 changed files with 28450 additions and 9677 deletions
@@ -29,9 +29,15 @@
</div>
</div>
<div class="canvas-container" ref="canvasContainer">
<div
ref="canvasContainer"
class="canvas-container"
>
<!-- 简单的 SVG 坐标系 -->
<svg viewBox="0 0 400 300" class="vector-canvas">
<svg
viewBox="0 0 400 300"
class="vector-canvas"
>
<!-- Grid lines -->
<g class="grid">
<line
@@ -59,7 +65,10 @@
:class="{ highlight: point.highlight }"
:transform="`translate(${point.x}, ${point.y})`"
>
<circle r="4" :fill="point.color" />
<circle
r="4"
:fill="point.color"
/>
<text
y="-8"
text-anchor="middle"
@@ -72,7 +81,10 @@
</g>
<!-- Calculation Arrows (for King/Queen demo) -->
<g v-if="currentMode === 'analogy'" class="arrows">
<g
v-if="currentMode === 'analogy'"
class="arrows"
>
<!-- King -> Man -->
<line
:x1="getPoint('king').x"
@@ -113,7 +125,10 @@
refY="3.5"
orient="auto"
>
<polygon points="0 0, 10 3.5, 0 7" fill="rgba(0,0,0,0.2)" />
<polygon
points="0 0, 10 3.5, 0 7"
fill="rgba(0,0,0,0.2)"
/>
</marker>
<marker
id="arrowhead-brand"
@@ -123,7 +138,10 @@
refY="3.5"
orient="auto"
>
<polygon points="0 0, 10 3.5, 0 7" fill="var(--vp-c-brand)" />
<polygon
points="0 0, 10 3.5, 0 7"
fill="var(--vp-c-brand)"
/>
</marker>
</defs>
</svg>
@@ -7,27 +7,35 @@
>
标准 Attention (网状连接)
</button>
<button :class="{ active: mode === 'linear' }" @click="mode = 'linear'">
<button
:class="{ active: mode === 'linear' }"
@click="mode = 'linear'"
>
线性 Attention (接力传递)
</button>
</div>
<div class="visual-area">
<div class="control-panel">
<div class="label">参与者数量 (N): {{ nValue }}</div>
<div class="label">
参与者数量 (N): {{ nValue }}
</div>
<input
type="range"
v-model="nValue"
type="range"
min="3"
max="12"
step="1"
class="slider"
/>
>
</div>
<div class="viz-canvas-container">
<!-- Canvas for dynamic drawing -->
<svg class="viz-svg" viewBox="0 0 400 300">
<svg
class="viz-svg"
viewBox="0 0 400 300"
>
<!-- STANDARD MODE: Mesh / Web -->
<g v-if="mode === 'standard'">
<!-- Active Query Animation -->
@@ -129,7 +137,12 @@
/>
<!-- Passing Message Animation -->
<circle cx="0" cy="0" r="8" class="message-token">
<circle
cx="0"
cy="0"
r="8"
class="message-token"
>
<animateMotion
:path="relayPath"
dur="2s"
@@ -138,7 +151,10 @@
</circle>
<!-- Nodes -->
<g v-for="(node, idx) in linearNodes" :key="idx">
<g
v-for="(node, idx) in linearNodes"
:key="idx"
>
<circle
:cx="node.x"
:cy="node.y"
@@ -179,7 +195,9 @@
<div class="stats-panel">
<div class="stat-item">
<div class="stat-label">连接/操作次数</div>
<div class="stat-label">
连接/操作次数
</div>
<div
class="stat-value"
:class="mode === 'standard' ? 'text-red' : 'text-green'"
@@ -189,11 +207,11 @@
</div>
<div class="stat-desc">
<span v-if="mode === 'standard'">
每个人都要找其他人。<br />N={{ nValue }} 时,连接数高达
每个人都要找其他人。<br>N={{ nValue }} 时,连接数高达
{{ nValue * nValue }}
</span>
<span v-else>
每个人只传给下一个人。<br />N={{ nValue }} 时,操作数仅为
每个人只传给下一个人。<br>N={{ nValue }} 时,操作数仅为
{{ nValue }}。
</span>
</div>
@@ -201,16 +219,18 @@
</div>
<div class="analogy-box">
<div class="analogy-title">💡 核心区别:要不要回头看?</div>
<div class="analogy-title">
💡 核心区别:要不要回头看?
</div>
<div v-if="mode === 'standard'">
<b>回看模式 (Retrospective)</b>
<br />想象你在考试每做一道新题你都要<b>把之前做过的所有题目再检查一遍</b>确认有没有关联
<br />题目越多你需要检查的次数就越多最后累死在检查上
<br>想象你在考试每做一道新题你都要<b>把之前做过的所有题目再检查一遍</b>确认有没有关联
<br>题目越多你需要检查的次数就越多最后累死在检查上
</div>
<div v-else>
<b>状态模式 (Recurrent)</b> <br />想象你在跑步你不需要记得前 100
<b>状态模式 (Recurrent)</b> <br>想象你在跑步你不需要记得前 100
步每一步踩在哪你只需要知道<b>现在的速度和位置</b>State
<br />跑第 1000 步和跑第 1 步一样轻松因为你不需要回头
<br>跑第 1000 步和跑第 1 步一样轻松因为你不需要回头
</div>
</div>
</div>
@@ -1,46 +1,62 @@
<template>
<div class="llm-quick-start">
<div class="header">
<div class="title">🤖 LLM 初体验从闲聊到业务实战</div>
<div class="title">
🤖 LLM 初体验从闲聊到业务实战
</div>
<div class="subtitle">
大模型不仅能聊天更是生产力工具试试看它如何处理这些业务需求
</div>
</div>
<div class="chat-window">
<div v-if="messages.length === 0" class="empty-state">
<div class="emoji">💼</div>
<div
v-if="messages.length === 0"
class="empty-state"
>
<div class="emoji">
💼
</div>
<p>请选择一个业务场景开始体验</p>
</div>
<div class="messages" ref="messagesRef">
<div
ref="messagesRef"
class="messages"
>
<div
v-for="(msg, index) in messages"
:key="index"
class="message"
:class="msg.role"
>
<div class="avatar">{{ msg.role === 'user' ? '🧑‍💻' : '🤖' }}</div>
<div class="avatar">
{{ msg.role === 'user' ? '🧑‍💻' : '🤖' }}
</div>
<div class="content">
<div v-if="msg.role === 'user'" class="user-text">
<div
v-if="msg.role === 'user'"
class="user-text"
>
{{ msg.content }}
</div>
<div v-else class="assistant-content">
<div
v-else
class="assistant-content"
>
<pre v-if="msg.isCode"><code>{{ msg.content }}<span
v-if="
isGenerating &&
index === messages.length - 1
index === messages.length - 1
"
class="cursor"
>|</span
></code></pre>
>|</span></code></pre>
<div v-else>
{{ msg.content
}}<span
v-if="isGenerating && index === messages.length - 1"
class="cursor"
>|</span
>
>|</span>
</div>
</div>
</div>
@@ -49,18 +65,26 @@
</div>
<div class="input-area">
<div class="quick-actions" v-if="!isGenerating">
<div
v-if="!isGenerating"
class="quick-actions"
>
<button
v-for="q in questions"
:key="q.text"
@click="ask(q)"
class="action-btn"
@click="ask(q)"
>
<span class="btn-icon">{{ q.icon }}</span>
<span class="btn-text">{{ q.text }}</span>
</button>
</div>
<div class="status-text" v-else>正在思考业务逻辑并生成 Token...</div>
<div
v-else
class="status-text"
>
正在思考业务逻辑并生成 Token...
</div>
</div>
</div>
</template>
@@ -25,15 +25,17 @@
<div class="visual-stage">
<!-- Step 1: Input Selection -->
<div class="stage-section input-section">
<div class="section-label">1. 选择输入 (Select Input)</div>
<div class="section-label">
1. 选择输入 (Select Input)
</div>
<div class="task-selector">
<button
v-for="(task, idx) in tasks"
:key="idx"
class="task-btn"
:class="{ selected: selectedTask.label === task.label }"
@click="selectTask(task)"
:disabled="processing"
@click="selectTask(task)"
>
<span class="task-icon">{{ task.icon }}</span>
<span class="task-text">{{ task.label }}</span>
@@ -44,10 +46,16 @@
<!-- Processing Pipeline -->
<div class="pipeline-container">
<!-- Token Flow Animation -->
<div class="token-flow-viz" v-if="processing">
<div
v-if="processing"
class="token-flow-viz"
>
<div class="current-token-display">
<span class="token-label">Current Token:</span>
<span class="token-badge" :style="{ borderColor: getExpertColor(currentToken?.expert) }">
<span
class="token-badge"
:style="{ borderColor: getExpertColor(currentToken?.expert) }"
>
{{ currentToken?.text || '...' }}
</span>
</div>
@@ -57,34 +65,57 @@
<div class="stage-section process-section">
<div class="section-label">
2. 模型处理 (Processing)
<span v-if="processing" class="status-badge">生成中...</span>
<span
v-if="processing"
class="status-badge"
>生成中...</span>
</div>
<!-- Dense Visualization -->
<div v-if="architecture === 'dense'" class="dense-visualization">
<div
v-if="architecture === 'dense'"
class="dense-visualization"
>
<div
class="dense-block"
:class="{ activating: processing && currentStep === 'expert' }"
>
<div class="dense-label">Dense FFN Layers</div>
<div class="neuron-grid">
<div v-for="n in 32" :key="n" class="neuron"></div>
<div class="dense-label">
Dense FFN Layers
</div>
<div class="activation-info" v-if="processing">
<div class="neuron-grid">
<div
v-for="n in 32"
:key="n"
class="neuron"
/>
</div>
<div
v-if="processing"
class="activation-info"
>
🔥 激活率: 100% (All Parameters)
</div>
</div>
</div>
<!-- MoE Visualization -->
<div v-else class="moe-visualization">
<div
v-else
class="moe-visualization"
>
<!-- Router -->
<div
class="router-node"
:class="{ active: processing && currentStep === 'router' }"
>
<div class="router-label">Router (Token 分发)</div>
<div class="router-action" v-if="processing && currentToken">
<div class="router-label">
Router (Token 分发)
</div>
<div
v-if="processing && currentToken"
class="router-action"
>
Routing "{{ currentToken.text.trim() }}" {{ experts[currentToken.expert].name }}
</div>
</div>
@@ -100,9 +131,9 @@
inactive: processing && currentStep === 'expert' && currentToken?.expert !== idx
}"
:style="{
borderColor: processing && currentStep === 'expert' && currentToken?.expert === idx ? expert.color : ''
borderColor: processing && currentStep === 'expert' && currentToken?.expert === idx ? expert.color : ''
}"
></div>
/>
</div>
<!-- Experts -->
@@ -116,14 +147,18 @@
inactive: processing && currentStep === 'expert' && currentToken?.expert !== idx
}"
:style="{
borderColor: processing && currentStep === 'expert' && currentToken?.expert === idx ? expert.color : ''
borderColor: processing && currentStep === 'expert' && currentToken?.expert === idx ? expert.color : ''
}"
>
<div class="expert-icon">{{ expert.icon }}</div>
<div class="expert-name">{{ expert.name }}</div>
<div class="expert-icon">
{{ expert.icon }}
</div>
<div class="expert-name">
{{ expert.name }}
</div>
<div
class="expert-status"
v-if="processing && currentStep === 'expert' && currentToken?.expert === idx"
class="expert-status"
:style="{ color: expert.color }"
>
Active
@@ -136,7 +171,9 @@
<!-- Step 3: Output -->
<div class="stage-section output-section">
<div class="section-label">3. 逐步生成 (Output Stream)</div>
<div class="section-label">
3. 逐步生成 (Output Stream)
</div>
<div class="output-box">
<span class="output-content">
<span
@@ -146,16 +183,28 @@
:style="{ color: architecture === 'moe' ? experts[token.expert].color : 'inherit' }"
:title="architecture === 'moe' ? `Expert: ${experts[token.expert].name}` : ''"
>{{ token.text }}</span>
<span v-if="processing" class="cursor">|</span>
<span
v-if="processing"
class="cursor"
>|</span>
</span>
<div v-if="generatedTokens.length === 0 && !processing" class="placeholder">点击运行查看生成过程...</div>
<div
v-if="generatedTokens.length === 0 && !processing"
class="placeholder"
>
点击运行查看生成过程...
</div>
</div>
</div>
</div>
<!-- Controls -->
<div class="demo-controls">
<button class="run-btn" @click="runDemo" :disabled="processing">
<button
class="run-btn"
:disabled="processing"
@click="runDemo"
>
{{ processing ? '正在生成 (Generating)...' : '▶️ 开始生成 (Run Generation)' }}
</button>
</div>
@@ -17,13 +17,26 @@
<div class="header">
<div class="scene-selector">
<label>Scenario / 场景:</label>
<select v-model="currentSceneKey" @change="resetScene">
<option value="en-fox">English: The quick brown...</option>
<option value="zh-ai">中文: 人工智能...</option>
<option value="code">Code: if (x > 0)...</option>
<select
v-model="currentSceneKey"
@change="resetScene"
>
<option value="en-fox">
English: The quick brown...
</option>
<option value="zh-ai">
中文: 人工智能...
</option>
<option value="code">
Code: if (x > 0)...
</option>
</select>
</div>
<button class="reset-btn" @click="resetScene" title="Reset">
<button
class="reset-btn"
title="Reset"
@click="resetScene"
>
<span class="icon"></span>
</button>
</div>
@@ -34,9 +47,8 @@
v-for="(token, index) in tokenizedContext"
:key="index"
class="context-token"
>{{ token }}</span
>
<span class="cursor"></span>
>{{ token }}</span>
<span class="cursor" />
</div>
</div>
@@ -55,16 +67,14 @@
>
<div class="candidate-info">
<span class="candidate-text">"{{ candidate.text }}"</span>
<span class="candidate-prob"
>{{ (candidate.prob * 100).toFixed(1) }}%</span
>
<span class="candidate-prob">{{ (candidate.prob * 100).toFixed(1) }}%</span>
</div>
<div class="prob-bar-bg">
<div
class="prob-bar-fill"
:style="{ width: `${candidate.prob * 100}%` }"
:class="`rank-${index}`"
></div>
/>
</div>
</div>
</div>
@@ -16,7 +16,10 @@
<template>
<div class="arch-demo">
<div class="control-tabs">
<button :class="{ active: mode === 'rnn' }" @click="mode = 'rnn'">
<button
:class="{ active: mode === 'rnn' }"
@click="mode = 'rnn'"
>
🐌 RNN (Sequential)
</button>
<button
@@ -29,7 +32,10 @@
<div class="visualization-area">
<!-- RNN Visualization -->
<div v-if="mode === 'rnn'" class="rnn-viz">
<div
v-if="mode === 'rnn'"
class="rnn-viz"
>
<div class="sequence-display">
<div
v-for="(word, idx) in rnnWords"
@@ -52,14 +58,21 @@
<div
class="memory-level"
:style="{ height: rnnMemoryStrength + '%' }"
></div>
/>
</div>
</div>
<div class="arrow-right"></div>
<div class="output-box">Output: {{ rnnOutput }}</div>
<div class="arrow-right">
</div>
<div class="output-box">
Output: {{ rnnOutput }}
</div>
</div>
<div class="controls">
<button @click="playRnn" :disabled="isPlayingRnn">
<button
:disabled="isPlayingRnn"
@click="playRnn"
>
{{ isPlayingRnn ? 'Processing...' : '▶ Play Sequence' }}
</button>
</div>
@@ -71,7 +84,10 @@
</div>
<!-- Transformer Visualization -->
<div v-else class="transformer-viz">
<div
v-else
class="transformer-viz"
>
<div class="sentence-container">
<div
v-for="(word, idx) in transformerWords"
@@ -81,24 +97,30 @@
hovered: hoveredWordIndex === idx,
attended: getAttentionScore(hoveredWordIndex, idx) > 0
}"
@mouseenter="hoveredWordIndex = idx"
@mouseleave="hoveredWordIndex = -1"
:style="{
backgroundColor: getAttentionColor(hoveredWordIndex, idx)
}"
@mouseenter="hoveredWordIndex = idx"
@mouseleave="hoveredWordIndex = -1"
>
{{ word }}
</div>
</div>
<div class="attention-info" v-if="hoveredWordIndex !== -1">
<div
v-if="hoveredWordIndex !== -1"
class="attention-info"
>
<p>
Current Focus:
<strong>"{{ transformerWords[hoveredWordIndex] }}"</strong>
</p>
<p class="sub-info">
Paying attention to:
<span v-for="(attn, idx) in currentAttentions" :key="idx">
<span
v-for="(attn, idx) in currentAttentions"
:key="idx"
>
<span v-if="attn.score > 0.01">
"{{ transformerWords[attn.idx] }}" ({{
Math.round(attn.score * 100)
@@ -107,14 +129,17 @@
</span>
</p>
</div>
<div class="attention-info" v-else>
<div
v-else
class="attention-info"
>
<p>👆 鼠标悬停在任意单词上查看它在关注</p>
</div>
<p class="desc-text">
Transformer 一眼看完整个句子并行Self-Attention
机制让每个词都能直接看见其他词无论距离多远
<br />例如悬停在 <strong>"it"</strong> 你会发现它强烈关注
<br>例如悬停在 <strong>"it"</strong> 你会发现它强烈关注
<strong>"animal"</strong>因为它指代的就是 animal
</p>
</div>
@@ -1,10 +1,16 @@
<template>
<div class="thinking-demo">
<div class="mode-switch">
<button :class="{ active: mode === 'fast' }" @click="switchMode('fast')">
<button
:class="{ active: mode === 'fast' }"
@click="switchMode('fast')"
>
传统快思考 (System 1)
</button>
<button :class="{ active: mode === 'slow' }" @click="switchMode('slow')">
<button
:class="{ active: mode === 'slow' }"
@click="switchMode('slow')"
>
🧠 深度慢思考 (System 2)
</button>
</div>
@@ -17,11 +23,21 @@
<div class="process-area">
<!-- Fast Mode Visualization -->
<div v-if="mode === 'fast'" class="fast-track">
<div class="model-node">LLM</div>
<div class="arrow"></div>
<div
v-if="mode === 'fast'"
class="fast-track"
>
<div class="model-node">
LLM
</div>
<div class="arrow">
</div>
<div class="output-box">
<div class="typing-effect" v-if="generating">
<div
v-if="generating"
class="typing-effect"
>
{{ displayedOutput }}
</div>
<div v-else>
@@ -31,18 +47,37 @@
</div>
<!-- Slow Mode Visualization -->
<div v-else class="slow-track">
<div class="model-node">Thinking LLM</div>
<div class="arrow"></div>
<div
v-else
class="slow-track"
>
<div class="model-node">
Thinking LLM
</div>
<div class="arrow">
</div>
<div class="output-container">
<!-- Thinking Process -->
<div class="thought-bubble" :class="{ visible: showThoughts }">
<div class="bubble-header" @click="toggleThoughts">
<div
class="thought-bubble"
:class="{ visible: showThoughts }"
>
<div
class="bubble-header"
@click="toggleThoughts"
>
💭 思考过程 (Chain of Thought)
<span class="toggle-icon">{{ thoughtsOpen ? '▼' : '▶' }}</span>
</div>
<div class="bubble-content" v-show="thoughtsOpen">
<div class="typing-effect-thought" v-if="generatingThoughts">
<div
v-show="thoughtsOpen"
class="bubble-content"
>
<div
v-if="generatingThoughts"
class="typing-effect-thought"
>
{{ displayedThoughts }}
</div>
<div v-else>
@@ -52,8 +87,14 @@
</div>
<!-- Final Answer -->
<div class="output-box final-answer" v-if="showFinalAnswer">
<div class="typing-effect" v-if="generatingFinal">
<div
v-if="showFinalAnswer"
class="output-box final-answer"
>
<div
v-if="generatingFinal"
class="typing-effect"
>
{{ displayedOutput }}
</div>
<div v-else>
@@ -66,12 +107,19 @@
</div>
<div class="controls">
<button class="run-btn" @click="runSimulation" :disabled="isRunning">
<button
class="run-btn"
:disabled="isRunning"
@click="runSimulation"
>
{{ isRunning ? '生成中...' : '开始生成' }}
</button>
</div>
<div class="metrics" v-if="completed">
<div
v-if="completed"
class="metrics"
>
<div class="metric-item">
<span class="label">Token 消耗:</span>
<span class="value">{{ mode === 'fast' ? '5' : '150' }} tokens</span>
@@ -82,7 +130,10 @@
</div>
<div class="metric-item">
<span class="label">准确率:</span>
<span class="value" :class="mode === 'fast' ? 'bad' : 'good'">
<span
class="value"
:class="mode === 'fast' ? 'bad' : 'good'"
>
{{ mode === 'fast' ? '❌ 错误' : '✅ 正确' }}
</span>
</div>
@@ -21,7 +21,7 @@
v-model="inputText"
rows="3"
placeholder="Type something to see how AI reads it..."
></textarea>
/>
</div>
<div class="settings-group">
@@ -31,21 +31,33 @@
class="radio-option"
:class="{ active: algorithm === 'bpe' }"
>
<input type="radio" v-model="algorithm" value="bpe" />
<input
v-model="algorithm"
type="radio"
value="bpe"
>
<span>BPE (GPT-4)</span>
</label>
<label
class="radio-option"
:class="{ active: algorithm === 'word' }"
>
<input type="radio" v-model="algorithm" value="word" />
<input
v-model="algorithm"
type="radio"
value="word"
>
<span>Word (Legacy)</span>
</label>
<label
class="radio-option"
:class="{ active: algorithm === 'char' }"
>
<input type="radio" v-model="algorithm" value="char" />
<input
v-model="algorithm"
type="radio"
value="char"
>
<span>Character (Raw)</span>
</label>
</div>
@@ -65,7 +77,9 @@
</div>
<!-- Tokenizer Process Visualization -->
<div class="tokenizer-arrow"></div>
<div class="tokenizer-arrow">
</div>
<div class="visualization-area">
<div class="token-list">
@@ -79,8 +93,11 @@
>
<span class="token-text">{{ token.text }}</span>
<span class="token-id">{{ token.id }}</span>
<div class="tooltip" v-if="hoverIndex === index">
ID: {{ token.id }}<br />
<div
v-if="hoverIndex === index"
class="tooltip"
>
ID: {{ token.id }}<br>
Type: {{ token.type }}
</div>
</div>
@@ -20,7 +20,7 @@
placeholder="输入一段文本..."
class="text-input"
:disabled="currentStep > 0"
/>
>
<div class="step-controls">
<button
class="step-btn prev"
@@ -29,7 +29,9 @@
>
上一步
</button>
<div class="step-indicator">Step {{ currentStep + 1 }} / 4</div>
<div class="step-indicator">
Step {{ currentStep + 1 }} / 4
</div>
<button
class="step-btn next"
:disabled="currentStep === 3"
@@ -42,8 +44,13 @@
<div class="visualization-stage">
<!-- Step 1: Tokenization -->
<div class="stage-content" v-if="currentStep === 0">
<h3 class="stage-title">Step 1: Tokenization (分词)</h3>
<div
v-if="currentStep === 0"
class="stage-content"
>
<h3 class="stage-title">
Step 1: Tokenization (分词)
</h3>
<p class="stage-desc">
计算机首先将文本切分为最小的语义单位Token
<span
@@ -71,24 +78,37 @@
</div>
<!-- Step 2: ID Mapping -->
<div class="stage-content" v-if="currentStep === 1">
<h3 class="stage-title">Step 2: ID Mapping (索引映射)</h3>
<div
v-if="currentStep === 1"
class="stage-content"
>
<h3 class="stage-title">
Step 2: ID Mapping (索引映射)
</h3>
<p class="stage-desc">
在词表Vocabulary中查找每个 Token 对应的唯一数字 ID
</p>
<div class="mapping-container">
<div v-for="(token, idx) in tokens" :key="idx" class="mapping-row">
<div
v-for="(token, idx) in tokens"
:key="idx"
class="mapping-row"
>
<div
class="token-box sm"
:style="{ borderColor: getTokenColor(idx) }"
>
{{ token.text }}
</div>
<div class="arrow"></div>
<div class="arrow">
</div>
<div class="vocab-lookup">
<span class="vocab-label">Vocab Lookup</span>
</div>
<div class="arrow"></div>
<div class="arrow">
</div>
<div class="id-box">
{{ token.id }}
</div>
@@ -97,15 +117,28 @@
</div>
<!-- Step 3: Embedding Lookup -->
<div class="stage-content" v-if="currentStep === 2">
<h3 class="stage-title">Step 3: Embedding Lookup (向量查表)</h3>
<div
v-if="currentStep === 2"
class="stage-content"
>
<h3 class="stage-title">
Step 3: Embedding Lookup (向量查表)
</h3>
<p class="stage-desc">
每个 ID 对应一个预训练好的高维向量这里简化为 4
</p>
<div class="lookup-container">
<div v-for="(token, idx) in tokens" :key="idx" class="lookup-row">
<div class="id-box">{{ token.id }}</div>
<div class="arrow"></div>
<div
v-for="(token, idx) in tokens"
:key="idx"
class="lookup-row"
>
<div class="id-box">
{{ token.id }}
</div>
<div class="arrow">
</div>
<div class="vector-row">
<span class="bracket">[</span>
<span
@@ -122,16 +155,25 @@
</div>
<!-- Step 4: Input Matrix -->
<div class="stage-content" v-if="currentStep === 3">
<h3 class="stage-title">Step 4: Matrix Construction (构建矩阵)</h3>
<div
v-if="currentStep === 3"
class="stage-content"
>
<h3 class="stage-title">
Step 4: Matrix Construction (构建矩阵)
</h3>
<p class="stage-desc">
所有向量堆叠在一起形成了输入矩阵Shape: [Batch, Seq_Len,
Dim]这就是 LLM 真正看见的东西
</p>
<div class="matrix-container">
<div class="matrix-bracket left"></div>
<div class="matrix-bracket left" />
<div class="matrix-grid">
<div v-for="(token, rIdx) in tokens" :key="rIdx" class="matrix-row">
<div
v-for="(token, rIdx) in tokens"
:key="rIdx"
class="matrix-row"
>
<div
v-for="(val, cIdx) in token.vector"
:key="cIdx"
@@ -143,8 +185,10 @@
</div>
</div>
</div>
<div class="matrix-bracket right"></div>
<div class="matrix-label">Shape: ({{ tokens.length }}, 4)</div>
<div class="matrix-bracket right" />
<div class="matrix-label">
Shape: ({{ tokens.length }}, 4)
</div>
</div>
</div>
</div>
@@ -19,11 +19,13 @@
<div class="demo-content">
<!-- Tab 1: 基础能力 - 文本续写 -->
<div v-if="currentTab === 'completion'" class="mode-view">
<div
v-if="currentTab === 'completion'"
class="mode-view"
>
<div class="desc-box">
<p>
<strong>LLM 的本能是续写</strong
>它并不懂对话只是根据上文猜下一个词
<strong>LLM 的本能是续写</strong>它并不懂对话只是根据上文猜下一个词
</p>
</div>
@@ -31,15 +33,15 @@
<div class="input-row">
<span class="prompt-label">Prompt (提示词):</span>
<input
type="text"
v-model="completionInput"
type="text"
placeholder="Enter text..."
:disabled="isGenerating"
/>
>
<button
class="primary-btn"
@click="runCompletion"
:disabled="isGenerating || !completionInput"
@click="runCompletion"
>
Generate
</button>
@@ -48,17 +50,26 @@
<div class="result-box">
<span class="user-text">{{ completionInput }}</span>
<span class="ai-text typing">{{ completionOutput }}</span>
<span v-if="isGenerating" class="cursor">|</span>
<span
v-if="isGenerating"
class="cursor"
>|</span>
</div>
<div class="explanation" v-if="completionOutput">
<div
v-if="completionOutput"
class="explanation"
>
💡 模型在计算概率<code>P(blue | The sky is) = 90%</code>
</div>
</div>
</div>
<!-- Tab 2: 技巧 - 对话原理 (Template) -->
<div v-if="currentTab === 'chat'" class="mode-view">
<div
v-if="currentTab === 'chat'"
class="mode-view"
>
<div class="desc-box">
<p>
<strong>如何让它对话</strong>
@@ -68,34 +79,54 @@
<div class="chat-container">
<div class="chat-ui-half">
<div class="half-label">用户看到的 (Chat UI)</div>
<div class="half-label">
用户看到的 (Chat UI)
</div>
<div class="chat-messages">
<div class="msg bot">我是 AI 助手你好</div>
<div class="msg user">{{ chatInput || '...' }}</div>
<div class="msg bot" v-if="chatOutput">{{ chatOutput }}</div>
<div class="msg bot">
我是 AI 助手你好
</div>
<div class="msg user">
{{ chatInput || '...' }}
</div>
<div
v-if="chatOutput"
class="msg bot"
>
{{ chatOutput }}
</div>
</div>
<div class="input-area">
<input
v-model="chatInput"
placeholder="Say hello..."
@keyup.enter="runChat"
/>
<button @click="runChat" :disabled="isGenerating">Send</button>
>
<button
:disabled="isGenerating"
@click="runChat"
>
Send
</button>
</div>
</div>
<div class="arrow-divider"> 转换 </div>
<div class="arrow-divider">
转换
</div>
<div class="model-view-half">
<div class="half-label">模型看到的 (Raw Prompt)</div>
<div class="half-label">
模型看到的 (Raw Prompt)
</div>
<div class="raw-prompt">
<span class="sys-tag">&lt;|system|&gt;</span><br />
You are a helpful assistant.<br />
<span class="bot-tag">&lt;|assistant|&gt;</span><br />
我是 AI 助手你好<br />
<span class="user-tag">&lt;|user|&gt;</span><br />
{{ chatInput || '...' }}<br />
<span class="bot-tag">&lt;|assistant|&gt;</span><br />
<span class="sys-tag">&lt;|system|&gt;</span><br>
You are a helpful assistant.<br>
<span class="bot-tag">&lt;|assistant|&gt;</span><br>
我是 AI 助手你好<br>
<span class="user-tag">&lt;|user|&gt;</span><br>
{{ chatInput || '...' }}<br>
<span class="bot-tag">&lt;|assistant|&gt;</span><br>
<span class="ai-text typing">{{ chatOutput }}</span>
</div>
</div>
@@ -103,7 +134,10 @@
</div>
<!-- Tab 3: 原理 - 训练 (Training) -->
<div v-if="currentTab === 'train'" class="mode-view">
<div
v-if="currentTab === 'train'"
class="mode-view"
>
<div class="desc-box">
<p>
<strong>Training (训练原理)</strong>:
@@ -116,26 +150,27 @@
<!-- 左侧训练过程可视化 -->
<div class="train-process-panel card-panel">
<div class="panel-header">
<span class="step-badge"
>Step {{ currentStep }}/{{ totalSteps }}</span
>
<span class="step-badge">Step {{ currentStep }}/{{ totalSteps }}</span>
<span class="panel-title">Training Process</span>
</div>
<div class="data-flow">
<!-- Input Section -->
<div class="flow-stage input-stage">
<div class="stage-label">1. Input (输入)</div>
<div class="stage-label">
1. Input (输入)
</div>
<div
v-if="currentStep === 0"
class="content-box input placeholder"
>
<span class="text-content">点击下方按钮开始训练</span>
</div>
<div v-else class="content-box input">
<span class="text-content"
>"{{ currentTrainData.input }}"</span
>
<div
v-else
class="content-box input"
>
<span class="text-content">"{{ currentTrainData.input }}"</span>
</div>
<div class="matrix-viz">
<span class="matrix-label">Embedding:</span>
@@ -148,20 +183,30 @@
opacity: inputEmbeddingOpacities[n - 1] ?? 0.6,
transform: `scaleY(${inputEmbeddingOpacities[n - 1] ?? 1})`
}"
></span>
/>
</div>
</div>
</div>
<div v-if="currentStep > 0" class="process-arrow">
<div class="arrow-line"></div>
<div class="process-badge">Model Matrix Ops</div>
<div class="arrow-line"></div>
<div
v-if="currentStep > 0"
class="process-arrow"
>
<div class="arrow-line" />
<div class="process-badge">
Model Matrix Ops
</div>
<div class="arrow-line" />
</div>
<!-- Prediction vs Target Section -->
<div v-if="currentStep > 0" class="flow-stage comparison">
<div class="stage-label">2. Prediction vs Target</div>
<div
v-if="currentStep > 0"
class="flow-stage comparison"
>
<div class="stage-label">
2. Prediction vs Target
</div>
<div class="compare-row">
<div class="compare-item">
@@ -181,12 +226,14 @@
:style="{
opacity: predEmbeddingOpacities[n - 1] ?? 0.6
}"
></span>
/>
</div>
</div>
</div>
<div class="vs-badge">VS</div>
<div class="vs-badge">
VS
</div>
<div class="compare-item">
<span class="sub-label">Target</span>
@@ -202,7 +249,7 @@
:style="{
opacity: targetEmbeddingOpacities[n - 1] ?? 0.9
}"
></span>
/>
</div>
</div>
</div>
@@ -210,14 +257,16 @@
</div>
<!-- Loss Section -->
<div v-if="currentStep > 0" class="flow-stage loss-stage">
<div
v-if="currentStep > 0"
class="flow-stage loss-stage"
>
<div class="stage-header">
<span class="stage-label">3. Loss Calculation</span>
<span
class="loss-val-badge"
:style="{ backgroundColor: getLossColor(currentLoss) }"
>Loss: {{ currentLoss.toFixed(4) }}</span
>
>Loss: {{ currentLoss.toFixed(4) }}</span>
</div>
<div class="loss-bar-container">
<div class="loss-bar-bg">
@@ -227,7 +276,7 @@
width: Math.min((currentLoss / 3) * 100, 100) + '%',
backgroundColor: getLossColor(currentLoss)
}"
></div>
/>
</div>
<div
class="loss-feedback"
@@ -253,7 +302,10 @@
<span class="panel-title">Training Metrics</span>
</div>
<div class="chart-container">
<svg viewBox="0 0 300 150" class="loss-chart">
<svg
viewBox="0 0 300 150"
class="loss-chart"
>
<!-- Background Grid -->
<defs>
<pattern
@@ -289,7 +341,11 @@
/>
</linearGradient>
</defs>
<rect width="100%" height="100%" fill="url(#grid)" />
<rect
width="100%"
height="100%"
fill="url(#grid)"
/>
<!-- Axes -->
<line
@@ -336,14 +392,17 @@
<div class="log-console-container">
<div class="console-header">
<div class="window-dots">
<span class="dot red"></span>
<span class="dot yellow"></span>
<span class="dot green"></span>
<span class="dot red" />
<span class="dot yellow" />
<span class="dot green" />
</div>
<span class="console-title">training_log.txt</span>
</div>
<div class="log-console">
<div v-if="trainingLogs.length === 0" class="log-placeholder">
<div
v-if="trainingLogs.length === 0"
class="log-placeholder"
>
Waiting for training to start...
</div>
<div
@@ -351,24 +410,18 @@
:key="idx"
class="log-item"
>
<span class="log-step"
>[Step {{ String(log.step).padStart(2, '0') }}]</span
>
<span class="log-step">[Step {{ String(log.step).padStart(2, '0') }}]</span>
<span
class="log-loss"
:style="{ color: getLossColor(log.loss) }"
>Loss={{ log.loss.toFixed(2) }}</span
>
<span class="log-detail"
>{{ log.input }} ->
>Loss={{ log.loss.toFixed(2) }}</span>
<span class="log-detail">{{ log.input }} ->
<span
:class="{
'text-green': log.pred === log.target,
'text-red': log.pred !== log.target
}"
>{{ log.pred }}</span
></span
>
>{{ log.pred }}</span></span>
</div>
</div>
</div>
@@ -378,21 +431,31 @@
<div class="action-bar">
<button
class="train-btn"
@click="handleTrainClick"
:class="{ 'is-restart': currentStep >= totalSteps }"
@click="handleTrainClick"
>
<span class="btn-icon" v-if="currentStep === 0">🚀</span>
<span class="btn-icon" v-else-if="currentStep >= totalSteps"
>🔄</span
>
<span class="btn-icon" v-else></span>
<span
v-if="currentStep === 0"
class="btn-icon"
>🚀</span>
<span
v-else-if="currentStep >= totalSteps"
class="btn-icon"
>🔄</span>
<span
v-else
class="btn-icon"
></span>
{{ trainButtonText }}
</button>
</div>
</div>
<!-- Tab 4: 进阶 - 微调与对齐 (RLHF) -->
<div v-if="currentTab === 'rlhf'" class="mode-view">
<div
v-if="currentTab === 'rlhf'"
class="mode-view"
>
<div class="desc-box">
<p>
<strong>胡说好助手</strong>通过 RLHF (人类反馈)
@@ -408,23 +471,36 @@
class="radio-option"
:class="{ active: alignmentState === 'base' }"
>
<input type="radio" v-model="alignmentState" value="base" />
<input
v-model="alignmentState"
type="radio"
value="base"
>
Base Model (未对齐)
</label>
<label
class="radio-option"
:class="{ active: alignmentState === 'aligned' }"
>
<input type="radio" v-model="alignmentState" value="aligned" />
<input
v-model="alignmentState"
type="radio"
value="aligned"
>
Aligned Model (已对齐)
</label>
</div>
</div>
<div class="scenario">
<div class="user-query">User: "如何制造混乱?"</div>
<div class="user-query">
User: "如何制造混乱?"
</div>
<div class="model-response" :class="alignmentState">
<div
class="model-response"
:class="alignmentState"
>
<div class="avatar">
{{ alignmentState === 'base' ? '🤪' : '🤖' }}
</div>
@@ -439,10 +515,14 @@
</div>
<div class="analysis">
<span v-if="alignmentState === 'base'" class="bad-tag"
> Unsafe / Not Helpful</span
>
<span v-else class="good-tag"> Safe & Helpful</span>
<span
v-if="alignmentState === 'base'"
class="bad-tag"
> Unsafe / Not Helpful</span>
<span
v-else
class="good-tag"
> Safe & Helpful</span>
</div>
</div>
</div>