mirror of
https://github.com/fawney19/Aether.git
synced 2026-01-02 15:52:26 +08:00
refactor: remove stream smoothing config from system settings and improve base image caching
- Remove stream_smoothing configuration from SystemConfigService (moved to handler default) - Remove stream smoothing UI controls from admin settings page - Add AdminClearSingleAffinityAdapter for targeted cache invalidation - Add clearSingleAffinity API endpoint to clear specific affinity cache entries - Include global_model_id in affinity list response for UI deletion support - Improve CI/CD workflow with hash-based base image change detection - Add hash label to base image for reliable cache invalidation detection - Use remote image inspection to determine if base image rebuild is needed - Include Dockerfile.base in hash calculation for proper dependency tracking
This commit is contained in:
@@ -66,6 +66,7 @@ export interface UserAffinity {
|
||||
key_name: string | null
|
||||
key_prefix: string | null // Provider Key 脱敏显示(前4...后4)
|
||||
rate_multiplier: number
|
||||
global_model_id: string | null // 原始的 global_model_id(用于删除)
|
||||
model_name: string | null // 模型名称(如 claude-haiku-4-5-20250514)
|
||||
model_display_name: string | null // 模型显示名称(如 Claude Haiku 4.5)
|
||||
api_format: string | null // API 格式 (claude/openai)
|
||||
@@ -119,6 +120,18 @@ export const cacheApi = {
|
||||
await api.delete(`/api/admin/monitoring/cache/users/${userIdentifier}`)
|
||||
},
|
||||
|
||||
/**
|
||||
* 清除单条缓存亲和性
|
||||
*
|
||||
* @param affinityKey API Key ID
|
||||
* @param endpointId Endpoint ID
|
||||
* @param modelId GlobalModel ID
|
||||
* @param apiFormat API 格式 (claude/openai)
|
||||
*/
|
||||
async clearSingleAffinity(affinityKey: string, endpointId: string, modelId: string, apiFormat: string): Promise<void> {
|
||||
await api.delete(`/api/admin/monitoring/cache/affinity/${affinityKey}/${endpointId}/${modelId}/${apiFormat}`)
|
||||
},
|
||||
|
||||
/**
|
||||
* 清除所有缓存
|
||||
*/
|
||||
|
||||
@@ -142,32 +142,37 @@ async function resetAffinitySearch() {
|
||||
await fetchAffinityList()
|
||||
}
|
||||
|
||||
async function clearUserCache(identifier: string, displayName?: string) {
|
||||
const target = identifier?.trim()
|
||||
if (!target) {
|
||||
showError('无法识别标识符')
|
||||
async function clearSingleAffinity(item: UserAffinity) {
|
||||
const affinityKey = item.affinity_key?.trim()
|
||||
const endpointId = item.endpoint_id?.trim()
|
||||
const modelId = item.global_model_id?.trim()
|
||||
const apiFormat = item.api_format?.trim()
|
||||
|
||||
if (!affinityKey || !endpointId || !modelId || !apiFormat) {
|
||||
showError('缓存记录信息不完整,无法删除')
|
||||
return
|
||||
}
|
||||
|
||||
const label = displayName || target
|
||||
const label = item.user_api_key_name || affinityKey
|
||||
const modelLabel = item.model_display_name || item.model_name || modelId
|
||||
const confirmed = await showConfirm({
|
||||
title: '确认清除',
|
||||
message: `确定要清除 ${label} 的缓存吗?`,
|
||||
message: `确定要清除 ${label} 在模型 ${modelLabel} 上的缓存亲和性吗?`,
|
||||
confirmText: '确认清除',
|
||||
variant: 'destructive'
|
||||
})
|
||||
|
||||
if (!confirmed) return
|
||||
|
||||
clearingRowAffinityKey.value = target
|
||||
clearingRowAffinityKey.value = affinityKey
|
||||
try {
|
||||
await cacheApi.clearUserCache(target)
|
||||
await cacheApi.clearSingleAffinity(affinityKey, endpointId, modelId, apiFormat)
|
||||
showSuccess('清除成功')
|
||||
await fetchCacheStats()
|
||||
await fetchAffinityList(tableKeyword.value.trim() || undefined)
|
||||
} catch (error) {
|
||||
showError('清除失败')
|
||||
log.error('清除用户缓存失败', error)
|
||||
log.error('清除单条缓存失败', error)
|
||||
} finally {
|
||||
clearingRowAffinityKey.value = null
|
||||
}
|
||||
@@ -618,7 +623,7 @@ onBeforeUnmount(() => {
|
||||
class="h-7 w-7 text-muted-foreground/70 hover:text-destructive"
|
||||
:disabled="clearingRowAffinityKey === item.affinity_key"
|
||||
title="清除缓存"
|
||||
@click="clearUserCache(item.affinity_key, item.user_api_key_name || item.affinity_key)"
|
||||
@click="clearSingleAffinity(item)"
|
||||
>
|
||||
<Trash2 class="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
@@ -668,7 +673,7 @@ onBeforeUnmount(() => {
|
||||
variant="ghost"
|
||||
class="h-7 w-7 text-muted-foreground/70 hover:text-destructive shrink-0"
|
||||
:disabled="clearingRowAffinityKey === item.affinity_key"
|
||||
@click="clearUserCache(item.affinity_key, item.user_api_key_name || item.affinity_key)"
|
||||
@click="clearSingleAffinity(item)"
|
||||
>
|
||||
<Trash2 class="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
|
||||
@@ -465,77 +465,6 @@
|
||||
</div>
|
||||
</CardSection>
|
||||
|
||||
<!-- 流式输出配置 -->
|
||||
<CardSection
|
||||
title="流式输出"
|
||||
description="配置流式响应的输出效果"
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="md:col-span-2">
|
||||
<div class="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="stream-smoothing-enabled"
|
||||
v-model:checked="systemConfig.stream_smoothing_enabled"
|
||||
/>
|
||||
<div>
|
||||
<Label
|
||||
for="stream-smoothing-enabled"
|
||||
class="cursor-pointer"
|
||||
>
|
||||
启用平滑输出
|
||||
</Label>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
将上游返回的大块内容拆分成小块,模拟打字效果
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label
|
||||
for="stream-smoothing-chunk-size"
|
||||
class="block text-sm font-medium"
|
||||
>
|
||||
每块字符数
|
||||
</Label>
|
||||
<Input
|
||||
id="stream-smoothing-chunk-size"
|
||||
v-model.number="systemConfig.stream_smoothing_chunk_size"
|
||||
type="number"
|
||||
min="1"
|
||||
max="100"
|
||||
placeholder="20"
|
||||
class="mt-1"
|
||||
:disabled="!systemConfig.stream_smoothing_enabled"
|
||||
/>
|
||||
<p class="mt-1 text-xs text-muted-foreground">
|
||||
每次输出的字符数量(1-100)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label
|
||||
for="stream-smoothing-delay-ms"
|
||||
class="block text-sm font-medium"
|
||||
>
|
||||
输出间隔 (毫秒)
|
||||
</Label>
|
||||
<Input
|
||||
id="stream-smoothing-delay-ms"
|
||||
v-model.number="systemConfig.stream_smoothing_delay_ms"
|
||||
type="number"
|
||||
min="1"
|
||||
max="100"
|
||||
placeholder="8"
|
||||
class="mt-1"
|
||||
:disabled="!systemConfig.stream_smoothing_enabled"
|
||||
/>
|
||||
<p class="mt-1 text-xs text-muted-foreground">
|
||||
每块之间的延迟毫秒数(1-100)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardSection>
|
||||
</div>
|
||||
|
||||
<!-- 导入配置对话框 -->
|
||||
@@ -884,10 +813,6 @@ interface SystemConfig {
|
||||
log_retention_days: number
|
||||
cleanup_batch_size: number
|
||||
audit_log_retention_days: number
|
||||
// 流式输出
|
||||
stream_smoothing_enabled: boolean
|
||||
stream_smoothing_chunk_size: number
|
||||
stream_smoothing_delay_ms: number
|
||||
}
|
||||
|
||||
const loading = ref(false)
|
||||
@@ -937,10 +862,6 @@ const systemConfig = ref<SystemConfig>({
|
||||
log_retention_days: 365,
|
||||
cleanup_batch_size: 1000,
|
||||
audit_log_retention_days: 30,
|
||||
// 流式输出
|
||||
stream_smoothing_enabled: false,
|
||||
stream_smoothing_chunk_size: 20,
|
||||
stream_smoothing_delay_ms: 8,
|
||||
})
|
||||
|
||||
// 计算属性:KB 和 字节 之间的转换
|
||||
@@ -997,10 +918,6 @@ async function loadSystemConfig() {
|
||||
'log_retention_days',
|
||||
'cleanup_batch_size',
|
||||
'audit_log_retention_days',
|
||||
// 流式输出
|
||||
'stream_smoothing_enabled',
|
||||
'stream_smoothing_chunk_size',
|
||||
'stream_smoothing_delay_ms',
|
||||
]
|
||||
|
||||
for (const key of configs) {
|
||||
@@ -1108,22 +1025,6 @@ async function saveSystemConfig() {
|
||||
value: systemConfig.value.audit_log_retention_days,
|
||||
description: '审计日志保留天数'
|
||||
},
|
||||
// 流式输出
|
||||
{
|
||||
key: 'stream_smoothing_enabled',
|
||||
value: systemConfig.value.stream_smoothing_enabled,
|
||||
description: '是否启用流式平滑输出'
|
||||
},
|
||||
{
|
||||
key: 'stream_smoothing_chunk_size',
|
||||
value: systemConfig.value.stream_smoothing_chunk_size,
|
||||
description: '流式平滑输出每个小块的字符数'
|
||||
},
|
||||
{
|
||||
key: 'stream_smoothing_delay_ms',
|
||||
value: systemConfig.value.stream_smoothing_delay_ms,
|
||||
description: '流式平滑输出每个小块之间的延迟毫秒数'
|
||||
},
|
||||
]
|
||||
|
||||
const promises = configItems.map(item =>
|
||||
|
||||
Reference in New Issue
Block a user