From 7dac749eff1df7a05062c08da490059b6f507382 Mon Sep 17 00:00:00 2001 From: iven Date: Tue, 5 May 2026 16:05:00 +0800 Subject: [PATCH] =?UTF-8?q?feat(ai):=20=E6=96=B0=E5=A2=9E=E9=A2=84?= =?UTF-8?q?=E7=AE=97=E7=8A=B6=E6=80=81=20+=20=E6=88=90=E6=9C=AC=E4=BC=B0?= =?UTF-8?q?=E7=AE=97=20API=20=E7=AB=AF=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 3 Task 25: - GET /ai/budget/status — 租户月度预算状态和告警等级 - GET /ai/cost/estimate — 按分析类型+模型估算单次成本 --- crates/erp-ai/src/handler/mod.rs | 36 ++++++++++++++++++++++++++++++++ crates/erp-ai/src/module.rs | 8 +++++++ 2 files changed, 44 insertions(+) diff --git a/crates/erp-ai/src/handler/mod.rs b/crates/erp-ai/src/handler/mod.rs index 604d3cf..058480d 100644 --- a/crates/erp-ai/src/handler/mod.rs +++ b/crates/erp-ai/src/handler/mod.rs @@ -558,6 +558,42 @@ where Ok(Json(ApiResponse::ok(result))) } +// === 成本与预算 === + +pub async fn budget_status( + State(state): State, + Extension(ctx): Extension, +) -> Result>, erp_core::error::AppError> +where + AiState: FromRef, + S: Clone + Send + Sync + 'static, +{ + require_permission(&ctx, "ai.usage.list")?; + let cost_svc = crate::service::cost::CostService::new(state.db.clone()); + let status = cost_svc.get_budget_status(ctx.tenant_id).await?; + Ok(Json(ApiResponse::ok(status))) +} + +#[derive(Debug, Deserialize)] +pub struct CostEstimateQuery { + pub analysis_type: String, + pub model: Option, +} + +pub async fn cost_estimate( + Extension(ctx): Extension, + Query(params): Query, +) -> Result>, erp_core::error::AppError> +where + AiState: FromRef, + S: Clone + Send + Sync + 'static, +{ + require_permission(&ctx, "ai.usage.list")?; + let model = params.model.unwrap_or_else(|| "claude-sonnet-4-6".to_string()); + let estimate = crate::service::cost::CostService::estimate_cost(¶ms.analysis_type, &model); + Ok(Json(ApiResponse::ok(estimate))) +} + // === SSE 流构建辅助 === fn build_sse_stream( diff --git a/crates/erp-ai/src/module.rs b/crates/erp-ai/src/module.rs index 373e783..173a64e 100644 --- a/crates/erp-ai/src/module.rs +++ b/crates/erp-ai/src/module.rs @@ -359,5 +359,13 @@ impl AiModule { "/ai/quota/summary", axum::routing::get(crate::handler::quota_summary), ) + .route( + "/ai/budget/status", + axum::routing::get(crate::handler::budget_status), + ) + .route( + "/ai/cost/estimate", + axum::routing::get(crate::handler::cost_estimate), + ) } }