Files
Genarrative/server-rs/crates/api-server/src/agc_models.rs
T
suzmii 4f3f0f24ff 接入AGC后台模型目录与对话模型选择
新增后台 AGC 模型目录、别名、启停和默认项管理

客户端设置页恢复原状,对话框右下角按别名选择模型

服务端按稳定模型标识映射并校验实际模型白名单

修复 AGC 配套后端端口漂移、启动等待和 SpacetimeDB 版本检查

补充迁移、文档、启动与模型选择测试
2026-09-05 19:10:49 +08:00

98 lines
3.5 KiB
Rust

use crate::{
admin::AuthenticatedAdmin, api_response::json_success_body, http_error::AppError,
request_context::RequestContext, state::AppState,
};
use axum::{
Json,
extract::{Extension, State},
http::StatusCode,
};
use module_runtime::AgcModelCatalog;
use shared_contracts::admin::{AdminAgcModel, AdminAgcModelCatalog};
pub(crate) async fn load_catalog(state: &AppState) -> Result<AgcModelCatalog, AppError> {
let json = state
.spacetime_client()
.read_agc_model_catalog()
.await
.map_err(|_| {
AppError::from_status(StatusCode::SERVICE_UNAVAILABLE).with_message("模型目录暂不可用")
})?;
let catalog: AgcModelCatalog = serde_json::from_str(&json).map_err(|_| {
AppError::from_status(StatusCode::SERVICE_UNAVAILABLE).with_message("模型目录格式无效")
})?;
catalog.validate().map_err(|message| {
AppError::from_status(StatusCode::SERVICE_UNAVAILABLE).with_message(message)
})?;
Ok(catalog)
}
pub async fn admin_get_agc_models(
State(state): State<AppState>,
Extension(context): Extension<RequestContext>,
Extension(_admin): Extension<AuthenticatedAdmin>,
) -> Result<Json<serde_json::Value>, AppError> {
Ok(json_success_body(
Some(&context),
catalog_dto(load_catalog(&state).await?),
))
}
pub async fn admin_save_agc_models(
State(state): State<AppState>,
Extension(context): Extension<RequestContext>,
Extension(_admin): Extension<AuthenticatedAdmin>,
Json(payload): Json<AdminAgcModelCatalog>,
) -> Result<Json<serde_json::Value>, AppError> {
let catalog = AgcModelCatalog {
revision: payload.revision,
default_model_id: payload.default_model_id,
models: payload
.models
.into_iter()
.map(|m| module_runtime::AgcModel {
id: m.id,
alias: m.alias,
model_id: m.model_id,
enabled: m.enabled,
})
.collect(),
};
catalog
.validate()
.map_err(|message| AppError::from_status(StatusCode::BAD_REQUEST).with_message(message))?;
let payload = serde_json::to_string(&catalog)
.map_err(|_| AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR))?;
let saved = state
.spacetime_client()
.save_agc_model_catalog(payload)
.await
.map_err(|error| {
if matches!(error, spacetime_client::SpacetimeClientError::Procedure(ref message) if message == module_runtime::AGC_MODEL_CATALOG_CONFLICT) {
AppError::from_status(StatusCode::CONFLICT).with_message("模型目录已被更新,请重新读取")
} else {
AppError::from_status(StatusCode::SERVICE_UNAVAILABLE).with_message("保存模型目录失败,请稍后重试")
}
})?;
let catalog: AgcModelCatalog = serde_json::from_str(&saved)
.map_err(|_| AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR))?;
Ok(json_success_body(Some(&context), catalog_dto(catalog)))
}
fn catalog_dto(catalog: AgcModelCatalog) -> AdminAgcModelCatalog {
AdminAgcModelCatalog {
revision: catalog.revision,
default_model_id: catalog.default_model_id,
models: catalog
.models
.into_iter()
.map(|m| AdminAgcModel {
id: m.id,
alias: m.alias,
model_id: m.model_id,
enabled: m.enabled,
})
.collect(),
}
}