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
@@ -1,13 +1,20 @@
<template>
<div class="attn-demo">
<div class="header">
<div class="title">Self-Attention Mechanism</div>
<div class="subtitle">自注意力机制全局信息交互</div>
<div class="title">
Self-Attention Mechanism
</div>
<div class="subtitle">
自注意力机制全局信息交互
</div>
</div>
<div class="visual-stage">
<!-- Grid Layout -->
<div class="grid-container" @mouseleave="hoverIndex = -1">
<div
class="grid-container"
@mouseleave="hoverIndex = -1"
>
<!-- SVG Layer for Connection Lines -->
<svg class="connections-layer">
<defs>
@@ -30,8 +37,8 @@
<g v-if="hoverIndex !== -1">
<line
v-for="(target, tIndex) in items"
:key="tIndex"
v-show="tIndex !== hoverIndex"
:key="tIndex"
:x1="getCenter(hoverIndex).x"
:y1="getCenter(hoverIndex).y"
:x2="getCenter(tIndex).x"
@@ -55,11 +62,11 @@
'is-strong-attn':
hoverIndex !== -1 && getAttentionScore(hoverIndex, index) > 0.5
}"
@mouseenter="hoverIndex = index"
:style="{
left: getCenter(index).x - 30 + 'px',
top: getCenter(index).y - 30 + 'px'
}"
@mouseenter="hoverIndex = index"
>
<div class="cell-content">
<span class="cell-icon">{{ item.icon }}</span>
@@ -67,8 +74,8 @@
</div>
<!-- Attention Score Badge -->
<div
class="attn-badge"
v-if="hoverIndex !== -1 && hoverIndex !== index"
class="attn-badge"
:style="{
opacity: Math.max(0.3, getAttentionScore(hoverIndex, index))
}"
@@ -80,11 +87,17 @@
<!-- Info Panel -->
<div class="info-panel">
<div v-if="hoverIndex === -1" class="placeholder-text">
<div
v-if="hoverIndex === -1"
class="placeholder-text"
>
<span class="cursor-icon">👆</span>
把鼠标悬停在任意方块上<br />观察它在"关注"
把鼠标悬停在任意方块上<br>观察它在"关注"
</div>
<div v-else class="active-info">
<div
v-else
class="active-info"
>
<div class="source-info">
<span class="label">当前 Patch:</span>
<div class="patch-tag">
@@ -93,11 +106,13 @@
</div>
<div class="attn-list">
<div class="list-header">Attention Weights (注意力权重)</div>
<div class="list-header">
Attention Weights (注意力权重)
</div>
<div
class="attn-item"
v-for="(score, idx) in getTopAttentions(hoverIndex)"
:key="idx"
class="attn-item"
>
<div class="item-left">
<span class="item-icon">{{ items[idx].icon }}</span>
@@ -108,7 +123,7 @@
<div
class="progress-fill"
:style="{ width: score * 100 + '%' }"
></div>
/>
</div>
<span class="score-text">{{ (score * 100).toFixed(0) }}%</span>
</div>
@@ -6,7 +6,7 @@
</div>
<div class="desc">
目标 Projector 学会翻译图像语言
<br />做法冻结 ViT LLM只训练 Projector
<br>做法冻结 ViT LLM只训练 Projector
</div>
</div>
@@ -14,77 +14,131 @@
<!-- Data Input -->
<div class="data-column">
<div class="data-item image-data">
<div class="data-icon">🖼</div>
<div class="data-label">图片<br />()</div>
<div class="data-icon">
🖼
</div>
<div class="data-label">
图片<br>()
</div>
</div>
<div class="data-item text-data">
<div class="data-icon">📝</div>
<div class="data-label">标题<br />("一只猫")</div>
<div class="data-icon">
📝
</div>
<div class="data-label">
标题<br>("一只猫")
</div>
</div>
</div>
<!-- Arrow Column -->
<div class="arrow-column">
<div class="arrow"></div>
<div class="arrow"></div>
<div class="arrow">
</div>
<div class="arrow">
</div>
</div>
<!-- Model Column -->
<div class="model-column">
<!-- Vision Branch -->
<div class="model-block frozen">
<div class="status-badge"> 冻结</div>
<div class="block-icon">👁</div>
<div class="block-name">ViT</div>
<div class="status-badge">
冻结
</div>
<div class="block-icon">
👁
</div>
<div class="block-name">
ViT
</div>
</div>
<div class="arrow-small"></div>
<div class="arrow-small">
</div>
<div class="model-block training">
<div class="status-badge fire">🔥 训练</div>
<div class="block-icon">🔌</div>
<div class="block-name">Projector</div>
<div class="status-badge fire">
🔥 训练
</div>
<div class="block-icon">
🔌
</div>
<div class="block-name">
Projector
</div>
</div>
<!-- Text Branch -->
<div class="model-block frozen text-model">
<div class="status-badge"> 冻结</div>
<div class="block-icon">🧠</div>
<div class="block-name">LLM</div>
<div class="status-badge">
冻结
</div>
<div class="block-icon">
🧠
</div>
<div class="block-name">
LLM
</div>
</div>
</div>
<!-- Arrow Column -->
<div class="arrow-column">
<div class="arrow"></div>
<div class="arrow"></div>
<div class="arrow">
</div>
<div class="arrow">
</div>
</div>
<!-- Vector Output -->
<div class="vector-column">
<div class="vector-item v-vector">
<div class="vector-icon">🟢</div>
<div class="vector-label">向量 V</div>
<div class="vector-icon">
🟢
</div>
<div class="vector-label">
向量 V
</div>
</div>
<div class="loss-connection">
<div class="loss-line"></div>
<div class="loss-box" :class="{ active: isCalculatingLoss }">
<div class="loss-label">Loss</div>
<div class="loss-desc">V T</div>
<div class="loss-line" />
<div
class="loss-box"
:class="{ active: isCalculatingLoss }"
>
<div class="loss-label">
Loss
</div>
<div class="loss-desc">
V T
</div>
</div>
<div class="loss-line"></div>
<div class="loss-line" />
</div>
<div class="vector-item t-vector">
<div class="vector-icon">🔵</div>
<div class="vector-label">向量 T</div>
<div class="vector-icon">
🔵
</div>
<div class="vector-label">
向量 T
</div>
</div>
</div>
</div>
<div class="controls">
<button class="play-btn" @click="nextStep">
<button
class="play-btn"
@click="nextStep"
>
{{ buttonText }}
</button>
<div class="step-desc">
@@ -3,44 +3,66 @@
<div class="demo-container">
<!-- Step 1: Patch -->
<div class="step-box">
<div class="label">1. Patch (16×16×3) (示意 / Toy)</div>
<div class="label">
1. Patch (16×16×3) (示意 / Toy)
</div>
<div class="grid-patch">
<div
v-for="n in patchCellCount"
:key="n"
class="pixel"
:style="{ backgroundColor: getPixelColor(n) }"
></div>
/>
</div>
<div class="desc">
16×16 像素 × 3 通道 = 768 标量值
</div>
<div class="desc">16×16 像素 × 3 通道 = 768 标量值</div>
</div>
<div class="arrow"></div>
<div class="arrow">
</div>
<!-- Step 2: Flattened -->
<div class="step-box">
<div class="label">2. Flatten</div>
<div class="label">
2. Flatten
</div>
<div class="vector-container">
<div
v-for="n in flattenSampleCount"
:key="n"
class="vector-cell"
:style="{ backgroundColor: getPixelColor(n) }"
></div>
<div class="vector-ellipsis"></div>
/>
<div class="vector-ellipsis">
</div>
</div>
<div class="desc">
得到 1×768 向量 (Vector)
</div>
<div class="desc">得到 1×768 向量 (Vector)</div>
</div>
<div class="arrow">× W</div>
<div class="arrow">
× W
</div>
<!-- Step 3: Projected -->
<div class="step-box">
<div class="label">3. Embedding</div>
<div class="embedding-container">
<div v-for="n in 8" :key="n" class="embed-cell"></div>
<div class="label">
3. Embedding
</div>
<div class="embedding-container">
<div
v-for="n in 8"
:key="n"
class="embed-cell"
/>
</div>
<div class="desc">
映射到 D (示意 D=8常见 D=768)
</div>
<div class="desc">映射到 D (示意 D=8常见 D=768)</div>
</div>
</div>
</div>
@@ -1,8 +1,14 @@
<template>
<div class="model-evolution-demo">
<div class="controls-header">
<div class="toggle-container" @click="toggleMode">
<div class="toggle-track" :class="{ active: isVLM }">
<div
class="toggle-container"
@click="toggleMode"
>
<div
class="toggle-track"
:class="{ active: isVLM }"
>
<div class="toggle-thumb">
{{ isVLM ? '👁️' : '🧠' }}
</div>
@@ -24,8 +30,13 @@
<div class="diagram-stage">
<div class="lanes">
<div class="lane lane-vision" v-show="isVLM">
<div class="lane-title">Vision Path (视觉路径)</div>
<div
v-show="isVLM"
class="lane lane-vision"
>
<div class="lane-title">
Vision Path (视觉路径)
</div>
<div class="lane-flow">
<div class="node input-node">
<span class="icon">🖼</span>
@@ -43,7 +54,9 @@
</div>
<span class="mini-arrow"></span>
<div class="token-box token-box-vision">
<div class="token-box-title">Vision Tokens (视觉 Token)</div>
<div class="token-box-title">
Vision Tokens (视觉 Token)
</div>
<div class="tokens">
<span class="token vision">v1</span>
<span class="token vision">v2</span>
@@ -55,7 +68,9 @@
</div>
<div class="lane lane-text">
<div class="lane-title">Text Path (文字路径)</div>
<div class="lane-title">
Text Path (文字路径)
</div>
<div class="lane-flow">
<div class="node input-node">
<span class="icon"></span>
@@ -68,7 +83,9 @@
</div>
<span class="mini-arrow"></span>
<div class="token-box">
<div class="token-box-title">Text Tokens (文字 Token)</div>
<div class="token-box-title">
Text Tokens (文字 Token)
</div>
<div class="tokens">
<span class="token text">t1</span>
<span class="token text">t2</span>
@@ -80,9 +97,14 @@
</div>
<div class="merge-stage">
<div class="merge-title">Token Sequence (输入序列)</div>
<div class="merge-title">
Token Sequence (输入序列)
</div>
<div class="sequence">
<div v-if="isVLM" class="sequence-row">
<div
v-if="isVLM"
class="sequence-row"
>
<span class="sequence-tag vision">Vision (视觉)</span>
<div class="tokens">
<span class="token vision">v1</span>
@@ -101,10 +123,8 @@
</div>
</div>
<div class="sequence-hint">
<span v-if="isVLM"
>Concat: [Vision Tokens] + [Text Tokens]
(拼接视觉在前文字在后)</span
>
<span v-if="isVLM">Concat: [Vision Tokens] + [Text Tokens]
(拼接视觉在前文字在后)</span>
<span v-else>Only [Text Tokens] (只有文字 Token)</span>
</div>
</div>
@@ -126,12 +146,23 @@
</div>
<div class="interactive-info">
<transition name="fade" mode="out-in">
<div class="info-card" v-if="!isVLM" key="llm">
<transition
name="fade"
mode="out-in"
>
<div
v-if="!isVLM"
key="llm"
class="info-card"
>
<h3>Standard LLM Flow (标准大模型流程)</h3>
<p>Prompt Embedding Token Sequence LLM Response</p>
</div>
<div class="info-card vlm-info" v-else key="vlm">
<div
v-else
key="vlm"
class="info-card vlm-info"
>
<h3>VLM = LLM + Vision Encoder (视觉大模型原理)</h3>
<ul>
<li><strong>ViT (The Eye):</strong> 把图片编码成视觉特征</li>
@@ -8,16 +8,16 @@
<div class="controls">
<button
class="action-btn"
@click="prevStep"
:disabled="currentStep === 0"
@click="prevStep"
>
上一步 (Prev)
</button>
<span class="step-indicator">Step {{ currentStep + 1 }} / 4</span>
<button
class="action-btn primary"
@click="nextStep"
:disabled="currentStep === 3"
@click="nextStep"
>
{{ currentStep === 3 ? '完成 (Done)' : '下一步 (Next) ➡' }}
</button>
@@ -41,21 +41,43 @@
'is-patchified': currentStep >= 2
}"
>
<div class="grid-overlay" v-if="currentStep === 1"></div>
<div v-for="n in 196" :key="n" class="patch" :style="getPatchStyle(n)">
<div
v-if="currentStep === 1"
class="grid-overlay"
/>
<div
v-for="n in 196"
:key="n"
class="patch"
:style="getPatchStyle(n)"
>
<!-- Show number only in Pixelated stage to represent 'digitization' -->
<span class="pixel-val" v-if="currentStep === 1">{{
<span
v-if="currentStep === 1"
class="pixel-val"
>{{
Math.floor(Math.random() * 9)
}}</span>
<!-- Show ID in Patchified stage -->
<span class="patch-id" v-if="currentStep >= 2">{{ n }}</span>
<span
v-if="currentStep >= 2"
class="patch-id"
>{{ n }}</span>
</div>
</div>
<div class="arrow-down" v-if="currentStep >= 3"></div>
<div
v-if="currentStep >= 3"
class="arrow-down"
>
</div>
<!-- 线性序列视图 -->
<div class="sequence-container" v-if="currentStep >= 3">
<div
v-if="currentStep >= 3"
class="sequence-container"
>
<div class="sequence-label">
Token Sequence: 196×D (每个 Token D 维向量)
</div>
@@ -65,7 +87,7 @@
:key="n"
class="mini-patch"
:style="getMiniPatchStyle(n)"
></div>
/>
</div>
</div>
</div>
@@ -3,31 +3,56 @@
<div class="demo-row">
<!-- Input Feature -->
<div class="grid-wrapper">
<div class="grid-title">Feature Vectors</div>
<div class="grid-title">
Feature Vectors
</div>
<div class="grid-box feature-grid">
<div v-for="n in 9" :key="'f' + n" class="cell feature-cell">V</div>
<div
v-for="n in 9"
:key="'f' + n"
class="cell feature-cell"
>
V
</div>
</div>
</div>
<div class="op">+</div>
<div class="op">
+
</div>
<!-- Positional Embedding -->
<div class="grid-wrapper">
<div class="grid-title">Position Embeddings</div>
<div class="grid-title">
Position Embeddings
</div>
<div class="grid-box pos-grid">
<div v-for="n in 9" :key="'p' + n" class="cell pos-cell">{{ n }}</div>
<div
v-for="n in 9"
:key="'p' + n"
class="cell pos-cell"
>
{{ n }}
</div>
</div>
</div>
<div class="op">=</div>
<div class="op">
=
</div>
<!-- Result -->
<div class="grid-wrapper">
<div class="grid-title">Input to Transformer</div>
<div class="grid-title">
Input to Transformer
</div>
<div class="grid-box result-grid">
<div v-for="n in 9" :key="'r' + n" class="cell result-cell">
<span class="v">V</span><span class="plus">+</span
><span class="p">{{ n }}</span>
<div
v-for="n in 9"
:key="'r' + n"
class="cell result-cell"
>
<span class="v">V</span><span class="plus">+</span><span class="p">{{ n }}</span>
</div>
</div>
</div>
@@ -5,10 +5,16 @@
<template>
<div class="projector-demo">
<div class="mode-switch">
<button :class="{ active: mode === 'linear' }" @click="mode = 'linear'">
<button
:class="{ active: mode === 'linear' }"
@click="mode = 'linear'"
>
Linear (LLaVA)
</button>
<button :class="{ active: mode === 'qformer' }" @click="mode = 'qformer'">
<button
:class="{ active: mode === 'qformer' }"
@click="mode = 'qformer'"
>
Q-Former (BLIP-2)
</button>
</div>
@@ -16,9 +22,15 @@
<div class="pipeline">
<!-- Input: Visual Tokens -->
<div class="stage">
<div class="label">Visual Tokens (ViT)</div>
<div class="label">
Visual Tokens (ViT)
</div>
<div class="token-container input">
<div v-for="n in 16" :key="n" class="token visual"></div>
<div
v-for="n in 16"
:key="n"
class="token visual"
/>
</div>
<div class="count">
{{ mode === 'linear' ? '256 Tokens' : '256 Tokens' }}
@@ -27,32 +39,40 @@
<!-- Process: The Projector -->
<div class="stage connector">
<div class="arrow-line"></div>
<div class="projector-box" :class="mode">
<div class="arrow-line" />
<div
class="projector-box"
:class="mode"
>
<div class="title">
{{ mode === 'linear' ? 'Linear Layer' : 'Q-Former' }}
</div>
<div class="desc">
{{ mode === 'linear' ? '直接映射 (1:1)' : '查询提取 (N:M)' }}
</div>
<div class="animation-dots" v-if="mode === 'qformer'">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div
v-if="mode === 'qformer'"
class="animation-dots"
>
<div class="dot" />
<div class="dot" />
<div class="dot" />
</div>
</div>
<div class="arrow-line"></div>
<div class="arrow-line" />
</div>
<!-- Output: LLM Tokens -->
<div class="stage">
<div class="label">LLM Tokens</div>
<div class="label">
LLM Tokens
</div>
<div class="token-container output">
<div
v-for="n in mode === 'linear' ? 16 : 4"
:key="n"
class="token llm"
></div>
/>
</div>
<div class="count">
{{
@@ -1,10 +1,16 @@
<template>
<div class="pipeline-demo">
<div class="stage-switch">
<button :class="{ active: stage === 1 }" @click="stage = 1">
<button
:class="{ active: stage === 1 }"
@click="stage = 1"
>
阶段一特征对齐
</button>
<button :class="{ active: stage === 2 }" @click="stage = 2">
<button
:class="{ active: stage === 2 }"
@click="stage = 2"
>
阶段二指令微调
</button>
</div>
@@ -12,29 +18,57 @@
<div class="pipeline-visual">
<!-- Image Input -->
<div class="component-box image-input">
<div class="icon">🖼</div>
<div class="name">Image</div>
<div class="icon">
🖼
</div>
<div class="name">
Image
</div>
</div>
<div class="arrow"></div>
<div class="arrow">
</div>
<!-- Vision Encoder -->
<div class="component-box encoder" :class="{ frozen: true }">
<div class="status-badge"> Frozen</div>
<div class="name">ViT</div>
<div class="desc">Vision Encoder</div>
<div
class="component-box encoder"
:class="{ frozen: true }"
>
<div class="status-badge">
Frozen
</div>
<div class="name">
ViT
</div>
<div class="desc">
Vision Encoder
</div>
</div>
<div class="arrow"></div>
<div class="arrow">
</div>
<!-- Projector -->
<div class="component-box projector" :class="{ training: true }">
<div class="status-badge fire">🔥 Train</div>
<div class="name">Projector</div>
<div class="desc">Adapter</div>
<div
class="component-box projector"
:class="{ training: true }"
>
<div class="status-badge fire">
🔥 Train
</div>
<div class="name">
Projector
</div>
<div class="desc">
Adapter
</div>
</div>
<div class="arrow"></div>
<div class="arrow">
</div>
<!-- LLM -->
<div
@@ -44,32 +78,64 @@
<div class="status-badge">
{{ stage === 1 ? '❄️ Frozen' : '🔥 Train' }}
</div>
<div class="name">LLM</div>
<div class="desc">Language Model</div>
<div class="name">
LLM
</div>
<div class="desc">
Language Model
</div>
</div>
<div class="arrow"></div>
<div class="arrow">
</div>
<!-- Output / Loss -->
<div class="component-box output">
<div class="name" v-if="stage === 1">Loss Calculation</div>
<div class="name" v-else>Text Generation</div>
<div class="desc" v-if="stage === 1">Contrastive Loss</div>
<div class="desc" v-else>Next Token Prediction</div>
<div
v-if="stage === 1"
class="name"
>
Loss Calculation
</div>
<div
v-else
class="name"
>
Text Generation
</div>
<div
v-if="stage === 1"
class="desc"
>
Contrastive Loss
</div>
<div
v-else
class="desc"
>
Next Token Prediction
</div>
</div>
</div>
<div class="data-example">
<div class="data-title">当前训练数据示例</div>
<div class="data-content" v-if="stage === 1">
<div class="data-title">
当前训练数据示例
</div>
<div
v-if="stage === 1"
class="data-content"
>
<code>&lt;Image: 🐱&gt;, &lt;Text: "一只猫"&gt;</code>
<p>任务让图像向量与文本向量距离变近</p>
</div>
<div class="data-content" v-else>
<code
>User: &lt;Image: 🐱&gt; 这只猫在干嘛<br />Assistant:
它在睡觉</code
>
<div
v-else
class="data-content"
>
<code>User: &lt;Image: 🐱&gt; 这只猫在干嘛<br>Assistant:
它在睡觉</code>
<p>任务根据图像和问题生成回答</p>
</div>
</div>
@@ -9,26 +9,46 @@
<div class="messages">
<!-- User Message -->
<div class="message user">
<div class="avatar">👤</div>
<div class="avatar">
👤
</div>
<div class="bubble">
<div class="image-upload">
<div class="placeholder-img">🐱</div>
<div class="placeholder-img">
🐱
</div>
</div>
<div class="text">
这只猫在做什么
</div>
<div class="text">这只猫在做什么</div>
</div>
</div>
<!-- Assistant Message -->
<div class="message assistant" v-if="step > 0">
<div class="avatar">🤖</div>
<div
v-if="step > 0"
class="message assistant"
>
<div class="avatar">
🤖
</div>
<div class="bubble">
<div v-if="step === 1" class="thinking">
<div
v-if="step === 1"
class="thinking"
>
<span class="icon">👁</span> 正在观察图片...
</div>
<div v-else-if="step === 2" class="thinking">
<div
v-else-if="step === 2"
class="thinking"
>
<span class="icon">🧠</span> 正在思考...
</div>
<div v-else class="content type-writer">
<div
v-else
class="content type-writer"
>
{{ typedText }}<span class="cursor">|</span>
</div>
</div>
@@ -20,7 +20,7 @@
</div>
<div class="arrow-section">
<div class="arrow-line"></div>
<div class="arrow-line" />
<div class="arrow-text">
Reshape for View: Grid Sequence (重排显示网格序列)
</div>
@@ -28,7 +28,9 @@
<!-- 2. Feature Vector Sequence -->
<div class="stage">
<div class="stage-label">2. Output Token Sequence (N×D) (输出序列)</div>
<div class="stage-label">
2. Output Token Sequence (N×D) (输出序列)
</div>
<div class="vector-sequence">
<div
v-for="(item, index) in items"
@@ -42,25 +44,27 @@
<div
class="v-cell"
:style="{ opacity: 0.9, background: item.color }"
></div>
/>
<div
class="v-cell"
:style="{ opacity: 0.7, background: item.color }"
></div>
/>
<div
class="v-cell"
:style="{ opacity: 0.5, background: item.color }"
></div>
/>
<div
class="v-cell"
:style="{ opacity: 0.8, background: item.color }"
></div>
/>
<div
class="v-cell"
:style="{ opacity: 0.6, background: item.color }"
></div>
/>
</div>
<div class="vector-idx">
{{ index + 1 }}
</div>
<div class="vector-idx">{{ index + 1 }}</div>
</div>
</div>
</div>
@@ -68,21 +72,28 @@
<!-- 3. Semantic Panel -->
<div class="semantic-panel">
<div v-if="activeIndex !== -1" class="semantic-content">
<div class="header" :style="{ borderColor: items[activeIndex].color }">
<div
v-if="activeIndex !== -1"
class="semantic-content"
>
<div
class="header"
:style="{ borderColor: items[activeIndex].color }"
>
<span class="large-icon">{{ items[activeIndex].icon }}</span>
<div class="title-group">
<span class="title"
>Token #{{ activeIndex + 1 }}:
{{ items[activeIndex].label }}</span
>
<span class="title">Token #{{ activeIndex + 1 }}:
{{ items[activeIndex].label }}</span>
<span class="subtitle">Type: {{ items[activeIndex].type }}</span>
</div>
</div>
<div class="desc">
<div class="vector-repr">
<span class="label">Vector Value:</span>
<span class="code" :style="{ color: items[activeIndex].color }">
<span
class="code"
:style="{ color: items[activeIndex].color }"
>
[0.{{ (Math.random() * 99).toFixed(0) }}, -0.{{
(Math.random() * 99).toFixed(0)
}}, 1.{{ (Math.random() * 99).toFixed(0) }}, ...]
@@ -94,11 +105,12 @@
</div>
</div>
</div>
<div v-else class="placeholder">
<div
v-else
class="placeholder"
>
<span class="hint-icon">👆</span>
<span class="hint-text"
>悬停在上方方块或向量上查看 ViT 输出的语义特征</span
>
<span class="hint-text">悬停在上方方块或向量上查看 ViT 输出的语义特征</span>
</div>
</div>
</div>
@@ -1,8 +1,12 @@
<template>
<div class="vlm-quick-start">
<div class="header">
<div class="title">👁 VLM 初体验不只是看图说话</div>
<div class="subtitle">选择不同场景体验多模态模型的多种能力</div>
<div class="title">
👁 VLM 初体验不只是看图说话
</div>
<div class="subtitle">
选择不同场景体验多模态模型的多种能力
</div>
</div>
<div class="scenario-tabs">
@@ -24,22 +28,39 @@
class="image-placeholder"
:class="{ loaded: hasImage, 'receipt-bg': currentScenario === 'ocr' }"
>
<div v-if="!hasImage" class="upload-prompt">
<div class="icon">🖼</div>
<button class="upload-btn" @click="loadImage">
<div
v-if="!hasImage"
class="upload-prompt"
>
<div class="icon">
🖼
</div>
<button
class="upload-btn"
@click="loadImage"
>
上传图片 (模拟)
</button>
</div>
<div v-else class="image-content">
<div
v-else
class="image-content"
>
<!-- Chat: Landscape -->
<div
v-if="currentScenario === 'chat'"
class="real-image-container landscape"
>
<div class="real-image">🏔</div>
<div class="sun"></div>
<div class="tree">🌲</div>
<div class="real-image">
🏔
</div>
<div class="sun">
</div>
<div class="tree">
🌲
</div>
</div>
<!-- Detection: Fruits -->
@@ -73,24 +94,42 @@
v-else-if="currentScenario === 'analysis'"
class="factory-image"
>
<div class="safety-sign"> 安全生产</div>
<div class="safety-sign">
安全生产
</div>
<div class="worker-container">
<span class="worker">👷</span>
<span class="helmet" v-if="true"></span>
<span
v-if="true"
class="helmet"
></span>
</div>
<div class="machinery">
</div>
<div class="machinery"></div>
</div>
<!-- OCR: Receipt -->
<div v-else class="receipt-image">
<div class="receipt-header">🧾 RECEIPT</div>
<div
v-else
class="receipt-image"
>
<div class="receipt-header">
🧾 RECEIPT
</div>
<div class="receipt-body">
<div class="line"><span>Coffee</span><span>$4.50</span></div>
<div class="line"><span>Bagel</span><span>$3.00</span></div>
<div class="line">
<span>Coffee</span><span>$4.50</span>
</div>
<div class="line">
<span>Bagel</span><span>$3.00</span>
</div>
<div class="line total">
<span>TOTAL</span><span>$7.50</span>
</div>
<div class="line date"><span>2023-10-24</span></div>
<div class="line date">
<span>2023-10-24</span>
</div>
</div>
</div>
@@ -103,8 +142,14 @@
<!-- Chat Area -->
<div class="chat-area">
<div class="messages" ref="messagesRef">
<div v-if="messages.length === 0" class="empty-text">
<div
ref="messagesRef"
class="messages"
>
<div
v-if="messages.length === 0"
class="empty-text"
>
{{ hasImage ? '图片已就绪,请选择指令' : '请先上传图片' }}
</div>
<div
@@ -114,38 +159,51 @@
:class="msg.role"
>
<div class="content">
<div v-if="msg.isJson" class="json-content">
<div
v-if="msg.isJson"
class="json-content"
>
<pre>{{ msg.content }}</pre>
</div>
<span v-else>{{ msg.content }}</span>
<span
v-if="
msg.role === 'assistant' &&
isGenerating &&
index === messages.length - 1
isGenerating &&
index === messages.length - 1
"
class="cursor"
>|</span
>
>|</span>
</div>
</div>
</div>
<div class="input-area">
<div class="quick-actions" v-if="hasImage && !isGenerating">
<div
v-if="hasImage && !isGenerating"
class="quick-actions"
>
<button
v-for="q in currentQuestions"
:key="q"
@click="ask(q)"
class="action-btn"
@click="ask(q)"
>
{{ q }}
</button>
</div>
<div class="status-text" v-else-if="isGenerating">
<div
v-else-if="isGenerating"
class="status-text"
>
AI 正在观察图片并思考...
</div>
<div class="status-text" v-else>等待图片上传...</div>
<div
v-else
class="status-text"
>
等待图片上传...
</div>
</div>
</div>
</div>