mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
feat: 手动代理节点支持、系统默认代理与跨格式流式 usage 提取
代理节点: - 支持手动添加代理节点(HTTP/HTTPS/SOCKS5),含地址、认证信息和区域标签 - 新增手动节点的 CRUD API 和前端管理界面 - 提供商代理配置从 URL 字符串迁移至代理节点选择器(proxy_node_id) - 新增系统默认代理节点设置,未单独配置代理的提供商自动回退使用 - 删除节点时自动清除系统默认代理引用并失效缓存 - 健康检查跳过手动节点(无心跳,始终在线) 流式处理: - CLI handler 跨格式转换时委托基类解析 Provider 原始事件的 usage - StreamProcessor 新增 _extract_usage_from_converted_event 从转换后事件补充提取 usage - 支持 Claude/OpenAI/OpenAI Responses/Gemini 多种 usage 格式
This commit is contained in:
@@ -94,6 +94,50 @@
|
||||
</div>
|
||||
</CardSection>
|
||||
|
||||
<!-- 网络代理 -->
|
||||
<CardSection
|
||||
title="网络代理"
|
||||
description="配置提供商出站请求的默认代理,仅影响大模型 API、余额查询、OAuth 等提供商请求"
|
||||
>
|
||||
<template #actions>
|
||||
<Button
|
||||
size="sm"
|
||||
:disabled="proxyConfigLoading || !hasProxyConfigChanges"
|
||||
@click="saveProxyConfig"
|
||||
>
|
||||
{{ proxyConfigLoading ? '保存中...' : '保存' }}
|
||||
</Button>
|
||||
</template>
|
||||
<div class="max-w-md">
|
||||
<Label class="block text-sm font-medium mb-1">
|
||||
默认代理节点
|
||||
</Label>
|
||||
<Select
|
||||
:model-value="systemConfig.system_proxy_node_id || '__direct__'"
|
||||
@update:model-value="(v: string) => systemConfig.system_proxy_node_id = v === '__direct__' ? null : v"
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="直连(不使用代理)" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="__direct__">
|
||||
直连(不使用代理)
|
||||
</SelectItem>
|
||||
<SelectItem
|
||||
v-for="node in proxyNodesStore.onlineNodes"
|
||||
:key="node.id"
|
||||
:value="node.id"
|
||||
>
|
||||
{{ node.name }}{{ node.region ? ` · ${node.region}` : '' }} ({{ node.ip }}:{{ node.port }})
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p class="mt-1 text-xs text-muted-foreground">
|
||||
对未单独配置代理的提供商生效,覆盖大模型 API 请求、余额查询、OAuth 刷新等。不影响系统内部接口。
|
||||
</p>
|
||||
</div>
|
||||
</CardSection>
|
||||
|
||||
<!-- 基础配置 -->
|
||||
<CardSection
|
||||
title="基础配置"
|
||||
@@ -1010,10 +1054,14 @@ import { PageHeader, PageContainer, CardSection } from '@/components/layout'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import { adminApi, type ConfigExportData, type ConfigImportResponse, type UsersExportData, type UsersImportResponse } from '@/api/admin'
|
||||
import { log } from '@/utils/logger'
|
||||
import { useProxyNodesStore } from '@/stores/proxy-nodes'
|
||||
|
||||
const { success, error } = useToast()
|
||||
const proxyNodesStore = useProxyNodesStore()
|
||||
|
||||
interface SystemConfig {
|
||||
// 网络代理
|
||||
system_proxy_node_id: string | null
|
||||
// 基础配置
|
||||
default_user_quota_usd: number
|
||||
rate_limit_per_minute: number
|
||||
@@ -1044,6 +1092,7 @@ interface SystemConfig {
|
||||
enable_oauth_token_refresh: boolean
|
||||
}
|
||||
|
||||
const proxyConfigLoading = ref(false)
|
||||
const basicConfigLoading = ref(false)
|
||||
const logConfigLoading = ref(false)
|
||||
const cleanupConfigLoading = ref(false)
|
||||
@@ -1074,6 +1123,8 @@ const usersMergeModeSelectOpen = ref(false)
|
||||
const systemVersion = ref<string>('')
|
||||
|
||||
const systemConfig = ref<SystemConfig>({
|
||||
// 网络代理
|
||||
system_proxy_node_id: null,
|
||||
// 基础配置
|
||||
default_user_quota_usd: 10.0,
|
||||
rate_limit_per_minute: 0,
|
||||
@@ -1171,6 +1222,7 @@ onMounted(async () => {
|
||||
await Promise.all([
|
||||
loadSystemConfig(),
|
||||
loadSystemVersion(),
|
||||
proxyNodesStore.ensureLoaded(),
|
||||
])
|
||||
})
|
||||
|
||||
@@ -1186,6 +1238,8 @@ async function loadSystemVersion() {
|
||||
async function loadSystemConfig() {
|
||||
try {
|
||||
const configs = [
|
||||
// 网络代理
|
||||
'system_proxy_node_id',
|
||||
// 基础配置
|
||||
'default_user_quota_usd',
|
||||
'rate_limit_per_minute',
|
||||
@@ -1239,6 +1293,31 @@ async function loadSystemConfig() {
|
||||
}
|
||||
}
|
||||
|
||||
const hasProxyConfigChanges = computed(() => {
|
||||
if (!originalConfig.value) return false
|
||||
return systemConfig.value.system_proxy_node_id !== originalConfig.value.system_proxy_node_id
|
||||
})
|
||||
|
||||
async function saveProxyConfig() {
|
||||
proxyConfigLoading.value = true
|
||||
try {
|
||||
await adminApi.updateSystemConfig(
|
||||
'system_proxy_node_id',
|
||||
systemConfig.value.system_proxy_node_id || null,
|
||||
'系统默认代理节点 ID'
|
||||
)
|
||||
if (originalConfig.value) {
|
||||
originalConfig.value.system_proxy_node_id = systemConfig.value.system_proxy_node_id
|
||||
}
|
||||
success('网络代理配置已保存')
|
||||
} catch (err) {
|
||||
error('保存代理配置失败')
|
||||
log.error('保存代理配置失败:', err)
|
||||
} finally {
|
||||
proxyConfigLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function saveBasicConfig() {
|
||||
basicConfigLoading.value = true
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user