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:
@@ -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"><|system|></span><br />
|
||||
You are a helpful assistant.<br />
|
||||
<span class="bot-tag"><|assistant|></span><br />
|
||||
我是 AI 助手,你好!<br />
|
||||
<span class="user-tag"><|user|></span><br />
|
||||
{{ chatInput || '...' }}<br />
|
||||
<span class="bot-tag"><|assistant|></span><br />
|
||||
<span class="sys-tag"><|system|></span><br>
|
||||
You are a helpful assistant.<br>
|
||||
<span class="bot-tag"><|assistant|></span><br>
|
||||
我是 AI 助手,你好!<br>
|
||||
<span class="user-tag"><|user|></span><br>
|
||||
{{ chatInput || '...' }}<br>
|
||||
<span class="bot-tag"><|assistant|></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>
|
||||
|
||||
Reference in New Issue
Block a user