feat(ai): AiState + AiModule (ErpModule impl + 权限 + 路由骨架)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
20
crates/erp-ai/src/handler/mod.rs
Normal file
20
crates/erp-ai/src/handler/mod.rs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
use axum::response::IntoResponse;
|
||||||
|
|
||||||
|
pub async fn stream_lab_report() -> impl IntoResponse {
|
||||||
|
"stub"
|
||||||
|
}
|
||||||
|
pub async fn stream_trends() -> impl IntoResponse {
|
||||||
|
"stub"
|
||||||
|
}
|
||||||
|
pub async fn stream_checkup_plan() -> impl IntoResponse {
|
||||||
|
"stub"
|
||||||
|
}
|
||||||
|
pub async fn stream_report_summary() -> impl IntoResponse {
|
||||||
|
"stub"
|
||||||
|
}
|
||||||
|
pub async fn list_analysis() -> impl IntoResponse {
|
||||||
|
"stub"
|
||||||
|
}
|
||||||
|
pub async fn get_analysis() -> impl IntoResponse {
|
||||||
|
"stub"
|
||||||
|
}
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
pub mod dto;
|
pub mod dto;
|
||||||
pub mod entity;
|
pub mod entity;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
pub mod handler;
|
||||||
|
pub mod module;
|
||||||
pub mod prompt;
|
pub mod prompt;
|
||||||
pub mod provider;
|
pub mod provider;
|
||||||
pub mod sanitization;
|
pub mod sanitization;
|
||||||
pub mod service;
|
pub mod service;
|
||||||
|
pub mod state;
|
||||||
|
|
||||||
pub use error::{AiError, AiResult};
|
pub use error::{AiError, AiResult};
|
||||||
|
pub use module::AiModule;
|
||||||
|
pub use state::AiState;
|
||||||
|
|||||||
108
crates/erp-ai/src/module.rs
Normal file
108
crates/erp-ai/src/module.rs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
|
use axum::Router;
|
||||||
|
use erp_core::module::{ErpModule, ModuleType, PermissionDescriptor};
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
pub struct AiModule;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl ErpModule for AiModule {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"ai"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn module_type(&self) -> ModuleType {
|
||||||
|
ModuleType::Builtin
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dependencies(&self) -> Vec<&str> {
|
||||||
|
vec!["health"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn permissions(&self) -> Vec<PermissionDescriptor> {
|
||||||
|
vec![
|
||||||
|
PermissionDescriptor {
|
||||||
|
code: "ai.analysis.list".into(),
|
||||||
|
name: "查看分析历史".into(),
|
||||||
|
description: "查看 AI 分析结果历史记录".into(),
|
||||||
|
module: "ai".into(),
|
||||||
|
},
|
||||||
|
PermissionDescriptor {
|
||||||
|
code: "ai.analysis.manage".into(),
|
||||||
|
name: "请求分析".into(),
|
||||||
|
description: "发起 AI 分析请求".into(),
|
||||||
|
module: "ai".into(),
|
||||||
|
},
|
||||||
|
PermissionDescriptor {
|
||||||
|
code: "ai.prompt.list".into(),
|
||||||
|
name: "查看 Prompt".into(),
|
||||||
|
description: "查看 AI Prompt 模板列表".into(),
|
||||||
|
module: "ai".into(),
|
||||||
|
},
|
||||||
|
PermissionDescriptor {
|
||||||
|
code: "ai.prompt.manage".into(),
|
||||||
|
name: "管理 Prompt".into(),
|
||||||
|
description: "创建/编辑/激活/回滚 Prompt 模板".into(),
|
||||||
|
module: "ai".into(),
|
||||||
|
},
|
||||||
|
PermissionDescriptor {
|
||||||
|
code: "ai.usage.list".into(),
|
||||||
|
name: "查看用量".into(),
|
||||||
|
description: "查看 AI 用量统计".into(),
|
||||||
|
module: "ai".into(),
|
||||||
|
},
|
||||||
|
PermissionDescriptor {
|
||||||
|
code: "ai.provider.manage".into(),
|
||||||
|
name: "管理提供商".into(),
|
||||||
|
description: "管理 AI 提供商配置".into(),
|
||||||
|
module: "ai".into(),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AiModule {
|
||||||
|
pub fn public_routes<S>() -> Router<S>
|
||||||
|
where
|
||||||
|
crate::state::AiState: axum::extract::FromRef<S>,
|
||||||
|
S: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
Router::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn protected_routes<S>() -> Router<S>
|
||||||
|
where
|
||||||
|
crate::state::AiState: axum::extract::FromRef<S>,
|
||||||
|
S: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
Router::new()
|
||||||
|
.route(
|
||||||
|
"/ai/analyze/lab-report",
|
||||||
|
axum::routing::post(crate::handler::stream_lab_report),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/ai/analyze/trends",
|
||||||
|
axum::routing::post(crate::handler::stream_trends),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/ai/analyze/checkup-plan",
|
||||||
|
axum::routing::post(crate::handler::stream_checkup_plan),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/ai/analyze/report-summary",
|
||||||
|
axum::routing::post(crate::handler::stream_report_summary),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/ai/analysis/history",
|
||||||
|
axum::routing::get(crate::handler::list_analysis),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/ai/analysis/{id}",
|
||||||
|
axum::routing::get(crate::handler::get_analysis),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
17
crates/erp-ai/src/state.rs
Normal file
17
crates/erp-ai/src/state.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use erp_core::events::EventBus;
|
||||||
|
use sea_orm::DatabaseConnection;
|
||||||
|
|
||||||
|
use crate::service::analysis::AnalysisService;
|
||||||
|
use crate::service::prompt::PromptService;
|
||||||
|
use crate::service::usage::UsageService;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AiState {
|
||||||
|
pub db: DatabaseConnection,
|
||||||
|
pub event_bus: EventBus,
|
||||||
|
pub analysis: Arc<AnalysisService>,
|
||||||
|
pub prompt: Arc<PromptService>,
|
||||||
|
pub usage: Arc<UsageService>,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user