mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
Hide capability tags from UI
This commit is contained in:
@@ -291,25 +291,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 能力标签 -->
|
||||
<div v-if="availableCapabilities.length > 0">
|
||||
<Label class="text-xs mb-1.5 block">能力标签</Label>
|
||||
<div class="flex flex-wrap gap-1.5">
|
||||
<button
|
||||
v-for="cap in availableCapabilities"
|
||||
:key="cap.name"
|
||||
type="button"
|
||||
class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md border text-sm transition-colors"
|
||||
:class="form.capabilities[cap.name]
|
||||
? 'bg-primary/10 border-primary/50 text-primary'
|
||||
: 'bg-card border-border hover:bg-muted/50 text-muted-foreground'"
|
||||
@click="form.capabilities[cap.name] = !form.capabilities[cap.name]"
|
||||
>
|
||||
{{ cap.display_name }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自动获取模型 -->
|
||||
<div class="space-y-3 py-2 px-3 rounded-md border border-border/60 bg-muted/30">
|
||||
<div class="flex items-center justify-between">
|
||||
@@ -376,7 +357,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, watch } from 'vue'
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import {
|
||||
Dialog,
|
||||
Button,
|
||||
@@ -394,17 +375,14 @@ import { useToast } from '@/composables/useToast'
|
||||
import { useFormDialog } from '@/composables/useFormDialog'
|
||||
import { parseApiError } from '@/utils/errorParser'
|
||||
import { parseNumberInput, parseNullableNumberInput } from '@/utils/form'
|
||||
import { log } from '@/utils/logger'
|
||||
import JsonImportInput from '@/components/common/JsonImportInput.vue'
|
||||
import {
|
||||
addProviderKey,
|
||||
updateProviderKey,
|
||||
getAllCapabilities,
|
||||
sortApiFormats,
|
||||
type EndpointAPIKey,
|
||||
type EndpointAPIKeyUpdate,
|
||||
type ProviderEndpoint,
|
||||
type CapabilityDefinition,
|
||||
type ProviderType
|
||||
} from '@/api/endpoints'
|
||||
import { formatApiFormat, normalizeApiFormatAlias, formatSupportsAuthOverride } from '@/api/endpoints/types/api-format'
|
||||
@@ -710,9 +688,6 @@ const authTypeSelectId = computed(() => `auth-type-${formNonce.value}`)
|
||||
const keyNameFieldName = computed(() => `key-name-field-${formNonce.value}`)
|
||||
const apiKeyFieldName = computed(() => `api-key-field-${formNonce.value}`)
|
||||
|
||||
// 可用的能力列表
|
||||
const availableCapabilities = ref<CapabilityDefinition[]>([])
|
||||
|
||||
// 新增密钥时默认不自动开启上游模型获取
|
||||
const defaultAutoFetchModels = computed(() => false)
|
||||
|
||||
@@ -732,7 +707,6 @@ const form = ref({
|
||||
max_probe_interval_minutes: 32,
|
||||
note: '',
|
||||
is_active: true,
|
||||
capabilities: {} as Record<string, boolean>,
|
||||
auto_fetch_models: false,
|
||||
model_include_patterns_text: '', // 包含规则文本(逗号分隔)
|
||||
model_exclude_patterns_text: '' // 排除规则文本(逗号分隔)
|
||||
@@ -789,19 +763,6 @@ watch(
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
|
||||
// 加载能力列表
|
||||
async function loadCapabilities() {
|
||||
try {
|
||||
availableCapabilities.value = await getAllCapabilities()
|
||||
} catch (err) {
|
||||
log.error('Failed to load capabilities:', err)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadCapabilities()
|
||||
})
|
||||
|
||||
// API 格式切换
|
||||
function toggleApiFormat(format: string) {
|
||||
const index = form.value.api_formats.indexOf(format)
|
||||
@@ -840,7 +801,6 @@ function resetForm() {
|
||||
max_probe_interval_minutes: 32,
|
||||
note: '',
|
||||
is_active: true,
|
||||
capabilities: {},
|
||||
auto_fetch_models: defaultAutoFetchModels.value,
|
||||
model_include_patterns_text: '',
|
||||
model_exclude_patterns_text: ''
|
||||
@@ -892,7 +852,6 @@ function loadKeyData() {
|
||||
max_probe_interval_minutes: props.editingKey.max_probe_interval_minutes ?? 32,
|
||||
note: props.editingKey.note || '',
|
||||
is_active: props.editingKey.is_active,
|
||||
capabilities: { ...(props.editingKey.capabilities || {}) },
|
||||
auto_fetch_models: props.editingKey.auto_fetch_models ?? false,
|
||||
model_include_patterns_text: (props.editingKey.model_include_patterns || []).join(', '),
|
||||
model_exclude_patterns_text: (props.editingKey.model_exclude_patterns || []).join(', ')
|
||||
@@ -979,15 +938,6 @@ async function handleSave() {
|
||||
return
|
||||
}
|
||||
|
||||
// 过滤出有效的能力配置(只包含值为 true 的)
|
||||
const activeCapabilities: Record<string, boolean> = {}
|
||||
for (const [key, value] of Object.entries(form.value.capabilities)) {
|
||||
if (value) {
|
||||
activeCapabilities[key] = true
|
||||
}
|
||||
}
|
||||
const capabilitiesData = Object.keys(activeCapabilities).length > 0 ? activeCapabilities : null
|
||||
|
||||
saving.value = true
|
||||
try {
|
||||
// 准备 rate_multipliers 数据:只保留已选中格式的倍率配置
|
||||
@@ -1025,7 +975,6 @@ async function handleSave() {
|
||||
max_probe_interval_minutes: form.value.max_probe_interval_minutes,
|
||||
note: form.value.note,
|
||||
is_active: form.value.is_active,
|
||||
capabilities: capabilitiesData,
|
||||
allowed_models: shouldClearAllowedModels ? null : undefined,
|
||||
auto_fetch_models: form.value.auto_fetch_models,
|
||||
model_include_patterns: parsePatternText(form.value.model_include_patterns_text),
|
||||
@@ -1059,7 +1008,6 @@ async function handleSave() {
|
||||
cache_ttl_minutes: form.value.cache_ttl_minutes,
|
||||
max_probe_interval_minutes: form.value.max_probe_interval_minutes,
|
||||
note: form.value.note,
|
||||
capabilities: capabilitiesData || undefined,
|
||||
auto_fetch_models: form.value.auto_fetch_models,
|
||||
model_include_patterns: parsePatternText(form.value.model_include_patterns_text),
|
||||
model_exclude_patterns: parsePatternText(form.value.model_exclude_patterns_text)
|
||||
|
||||
@@ -341,36 +341,6 @@
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="activeCapabilities.length > 0"
|
||||
class="info-item"
|
||||
>
|
||||
<span class="info-label">请求能力</span>
|
||||
<span class="info-value">
|
||||
<span class="capability-tags">
|
||||
<span
|
||||
v-for="cap in activeCapabilities"
|
||||
:key="`required-${cap}`"
|
||||
class="capability-tag active"
|
||||
>{{ formatCapabilityLabel(cap) }}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="keyCapabilities.length > 0"
|
||||
class="info-item"
|
||||
>
|
||||
<span class="info-label">Key 能力</span>
|
||||
<span class="info-value">
|
||||
<span class="capability-tags">
|
||||
<span
|
||||
v-for="cap in keyCapabilities"
|
||||
:key="`key-${cap}`"
|
||||
class="capability-tag"
|
||||
>{{ formatCapabilityLabel(cap) }}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -1489,26 +1459,6 @@ const currentAttemptExtraDataDisplay = computed<Record<string, unknown> | null>(
|
||||
return Object.keys(display).length > 0 ? display : null
|
||||
})
|
||||
|
||||
// 计算当前尝试启用的能力标签(请求需要的能力)
|
||||
const activeCapabilities = computed(() => {
|
||||
if (!currentAttempt.value?.required_capabilities) return []
|
||||
const caps = currentAttempt.value.required_capabilities
|
||||
// 只返回值为 true 的能力
|
||||
return Object.entries(caps)
|
||||
.filter(([_, enabled]) => enabled)
|
||||
.map(([key]) => key)
|
||||
})
|
||||
|
||||
// 计算当前 Key 支持的能力标签
|
||||
const keyCapabilities = computed(() => {
|
||||
if (!currentAttempt.value?.key_capabilities) return []
|
||||
const caps = currentAttempt.value.key_capabilities
|
||||
// 只返回值为 true 的能力
|
||||
return Object.entries(caps)
|
||||
.filter(([_, enabled]) => enabled)
|
||||
.map(([key]) => key)
|
||||
})
|
||||
|
||||
const hasActiveImageProgress = computed(() => {
|
||||
return rawTimeline.value.some((candidate) => {
|
||||
const progress = normalizeImageProgress(candidate.image_progress)
|
||||
@@ -1542,20 +1492,6 @@ const formatAuthTypeWithPlan = (authType: string, planType?: string): string =>
|
||||
return typeName
|
||||
}
|
||||
|
||||
// 格式化能力标签显示
|
||||
const formatCapabilityLabel = (cap: string): string => {
|
||||
const labels: Record<string, string> = {
|
||||
'cache_1h': '1h缓存',
|
||||
'cache_5min': '5min缓存',
|
||||
'context_1m': '1M上下文',
|
||||
'context_200k': '200K上下文',
|
||||
'extended_thinking': '深度思考',
|
||||
'vision': '视觉',
|
||||
'function_calling': '函数调用',
|
||||
}
|
||||
return labels[cap] || cap
|
||||
}
|
||||
|
||||
const poolSelectionLabel = (reason: string): string => {
|
||||
const labels: Record<string, string> = {
|
||||
sticky: '粘性会话',
|
||||
@@ -2502,35 +2438,6 @@ function getDisplayStatus(attempt: CandidateRecord | null | undefined): string {
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
|
||||
/* 能力标签 */
|
||||
.capability-tags {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
.capability-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.15rem 0.5rem;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 500;
|
||||
color: hsl(var(--muted-foreground));
|
||||
white-space: nowrap;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
border: 1px dashed hsl(var(--border));
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
/* 被请求使用的能力(高亮边框) */
|
||||
.capability-tag.active {
|
||||
color: hsl(var(--primary));
|
||||
border-color: hsl(var(--primary) / 0.5);
|
||||
background: hsl(var(--primary) / 0.08);
|
||||
}
|
||||
|
||||
.image-progress-block {
|
||||
margin-top: 0.875rem;
|
||||
padding: 0.75rem;
|
||||
|
||||
Reference in New Issue
Block a user