mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-05 00:47:48 +08:00
feat: provider api_formats 可空继承、OpenAI 图片 edit/variation 与用量配额多项补强
- 鉴权: provider_api_keys.api_formats 改为可空,OAuth 托管 key 自动继承 provider endpoints 激活格式,相关 handler/测试同步更新 - 图片 planner: OpenAI 图片路由新增 edit/variation 操作并完善参数校验、响应合并与流式处理 - 用量: user me usage 返回区分 client_requested_stream/upstream_is_stream,前端 usage 列表筛选与展示增强 - 统计: stats_daily_model 新增 cache_creation_ephemeral_5m/1h tokens 字段与回填链路 - 配额/observability: quota repository 新增内存与 SQL 扩展,admin observability usage 字段扩充 - 其它: OAuth 导入/轮询收敛、provider 汇总与 pool admin 读写链路小修、新增 system_config 缓存与 provider template handler Closes #318 Co-authored-by: Entropy.Xu <[email protected]>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use crate::handlers::admin::request::AdminAppState;
|
||||
use crate::handlers::public::provider_key_api_formats;
|
||||
use crate::provider_key_auth::provider_key_effective_api_formats;
|
||||
use aether_scheduler_core::count_recent_rpm_requests_for_provider_key_since;
|
||||
use serde_json::json;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
@@ -18,6 +18,16 @@ pub(crate) async fn build_admin_key_health_payload(
|
||||
.await
|
||||
.ok()
|
||||
.and_then(|mut keys| keys.drain(..).next())?;
|
||||
let provider = state
|
||||
.read_provider_catalog_providers_by_ids(std::slice::from_ref(&key.provider_id))
|
||||
.await
|
||||
.ok()
|
||||
.and_then(|mut providers| providers.drain(..).next())?;
|
||||
let endpoints = state
|
||||
.list_provider_catalog_endpoints_by_provider_ids(std::slice::from_ref(&key.provider_id))
|
||||
.await
|
||||
.ok()
|
||||
.unwrap_or_default();
|
||||
|
||||
let request_count = key.request_count.unwrap_or(0);
|
||||
let success_count = key.success_count.unwrap_or(0);
|
||||
@@ -97,7 +107,9 @@ pub(crate) async fn build_admin_key_health_payload(
|
||||
.unwrap_or(0));
|
||||
} else {
|
||||
let mut formats_payload = serde_json::Map::new();
|
||||
for format_name in provider_key_api_formats(&key) {
|
||||
for format_name in
|
||||
provider_key_effective_api_formats(&key, &provider.provider_type, &endpoints)
|
||||
{
|
||||
let health_data = health_by_format.and_then(|formats| formats.get(&format_name));
|
||||
let circuit_data = circuit_by_format.and_then(|formats| formats.get(&format_name));
|
||||
let is_open = circuit_data
|
||||
@@ -363,11 +375,27 @@ pub(crate) async fn recover_all_admin_key_health(
|
||||
if !updated {
|
||||
continue;
|
||||
}
|
||||
let provider = state
|
||||
.read_provider_catalog_providers_by_ids(std::slice::from_ref(&key.provider_id))
|
||||
.await
|
||||
.ok()
|
||||
.and_then(|mut providers| providers.drain(..).next());
|
||||
let endpoints = state
|
||||
.list_provider_catalog_endpoints_by_provider_ids(std::slice::from_ref(&key.provider_id))
|
||||
.await
|
||||
.ok()
|
||||
.unwrap_or_default();
|
||||
let api_formats = provider
|
||||
.as_ref()
|
||||
.map(|provider| {
|
||||
provider_key_effective_api_formats(&key, &provider.provider_type, &endpoints)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
payload_items.push(json!({
|
||||
"key_id": key.id,
|
||||
"key_name": key.name,
|
||||
"provider_id": key.provider_id,
|
||||
"api_formats": key.api_formats.unwrap_or_else(|| json!([])),
|
||||
"api_formats": api_formats,
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use crate::handlers::admin::request::AdminAppState;
|
||||
use crate::handlers::admin::shared::unix_secs_to_rfc3339;
|
||||
use crate::handlers::public::{
|
||||
api_format_display_name, build_public_health_timeline, provider_key_api_formats,
|
||||
};
|
||||
use crate::handlers::public::{api_format_display_name, build_public_health_timeline};
|
||||
use crate::handlers::shared::unix_ms_to_rfc3339;
|
||||
use crate::provider_key_auth::provider_key_effective_api_formats;
|
||||
use aether_data_contracts::repository::candidates::PublicHealthTimelineBucket;
|
||||
use aether_scheduler_core::{is_provider_key_circuit_open, provider_key_health_score};
|
||||
use serde_json::json;
|
||||
@@ -50,17 +49,26 @@ pub(crate) async fn build_admin_endpoint_health_status_payload(
|
||||
let mut endpoint_to_format = BTreeMap::<String, String>::new();
|
||||
let mut provider_ids_by_format = BTreeMap::<String, BTreeSet<String>>::new();
|
||||
let mut active_provider_formats = BTreeSet::<(String, String)>::new();
|
||||
let provider_type_by_id = providers
|
||||
.iter()
|
||||
.map(|provider| (provider.id.clone(), provider.provider_type.clone()))
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let mut active_endpoints_by_provider = BTreeMap::<String, Vec<_>>::new();
|
||||
for endpoint in active_endpoints {
|
||||
endpoint_to_format.insert(endpoint.id.clone(), endpoint.api_format.clone());
|
||||
endpoint_ids_by_format
|
||||
.entry(endpoint.api_format.clone())
|
||||
.or_default()
|
||||
.push(endpoint.id);
|
||||
.push(endpoint.id.clone());
|
||||
provider_ids_by_format
|
||||
.entry(endpoint.api_format.clone())
|
||||
.or_default()
|
||||
.insert(endpoint.provider_id.clone());
|
||||
active_provider_formats.insert((endpoint.provider_id, endpoint.api_format));
|
||||
active_provider_formats.insert((endpoint.provider_id.clone(), endpoint.api_format.clone()));
|
||||
active_endpoints_by_provider
|
||||
.entry(endpoint.provider_id.clone())
|
||||
.or_default()
|
||||
.push(endpoint);
|
||||
}
|
||||
let all_endpoint_ids = endpoint_to_format.keys().cloned().collect::<Vec<_>>();
|
||||
|
||||
@@ -74,7 +82,15 @@ pub(crate) async fn build_admin_endpoint_health_status_payload(
|
||||
.ok()
|
||||
.unwrap_or_default();
|
||||
for key in keys {
|
||||
for api_format in provider_key_api_formats(&key) {
|
||||
let provider_type = provider_type_by_id
|
||||
.get(&key.provider_id)
|
||||
.map(String::as_str)
|
||||
.unwrap_or("");
|
||||
let endpoints = active_endpoints_by_provider
|
||||
.get(&key.provider_id)
|
||||
.map(Vec::as_slice)
|
||||
.unwrap_or(&[]);
|
||||
for api_format in provider_key_effective_api_formats(&key, provider_type, endpoints) {
|
||||
if !active_provider_formats.contains(&(key.provider_id.clone(), api_format.clone()))
|
||||
{
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user