docs(ai): 实施计划 Chunk 5 (Handler/State/Module + erp-server 集成)
This commit is contained in:
@@ -1691,3 +1691,276 @@ git commit -m "feat(ai): AnalysisService 核心编排 + PromptService + UsageSer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Chunk 5: Handler + State + Module + erp-server 集成
|
||||
|
||||
### Task 9: State + Module 定义
|
||||
|
||||
**Files:**
|
||||
- Create: `crates/erp-ai/src/state.rs`
|
||||
- Create: `crates/erp-ai/src/module.rs`
|
||||
|
||||
- [ ] **Step 1: 创建 state.rs**
|
||||
|
||||
```rust
|
||||
// crates/erp-ai/src/state.rs
|
||||
use std::sync::Arc;
|
||||
|
||||
use erp_core::EventBus;
|
||||
use sea_orm::DatabaseConnection;
|
||||
|
||||
use crate::provider::AiProvider;
|
||||
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>,
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 创建 module.rs — ErpModule + 路由注册**
|
||||
|
||||
```rust
|
||||
// crates/erp-ai/src/module.rs
|
||||
use async_trait::async_trait;
|
||||
use axum::Router;
|
||||
use erp_core::module::{ErpModule, ModuleContext, ModuleType, PermissionDescriptor};
|
||||
use erp_core::AppResult;
|
||||
use std::any::Any;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::handler;
|
||||
|
||||
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"] }
|
||||
|
||||
async fn on_startup(&self, _ctx: &ModuleContext) -> AppResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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(handler::stream_lab_report::<S>))
|
||||
.route("/ai/analyze/trends", axum::routing::post(handler::stream_trends::<S>))
|
||||
.route("/ai/analyze/checkup-plan", axum::routing::post(handler::stream_checkup_plan::<S>))
|
||||
.route("/ai/analyze/report-summary", axum::routing::post(handler::stream_report_summary::<S>))
|
||||
.route("/ai/analysis/history", axum::routing::get(handler::list_analysis::<S>))
|
||||
.route("/ai/analysis/{id}", axum::routing::get(handler::get_analysis::<S>))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 更新 lib.rs 添加 re-export**
|
||||
|
||||
```rust
|
||||
pub use module::AiModule;
|
||||
pub use state::AiState;
|
||||
```
|
||||
|
||||
以及 `pub mod module; pub mod state;`
|
||||
|
||||
- [ ] **Step 4: 验证编译 (handler 还没写,先创建 stub)**
|
||||
|
||||
创建 `crates/erp-ai/src/handler/mod.rs`:
|
||||
|
||||
```rust
|
||||
// crates/erp-ai/src/handler/mod.rs — stub,Chunk 6 完善
|
||||
use axum::response::IntoResponse;
|
||||
|
||||
pub async fn stream_lab_report<S>() -> impl IntoResponse { "stub" }
|
||||
pub async fn stream_trends<S>() -> impl IntoResponse { "stub" }
|
||||
pub async fn stream_checkup_plan<S>() -> impl IntoResponse { "stub" }
|
||||
pub async fn stream_report_summary<S>() -> impl IntoResponse { "stub" }
|
||||
pub async fn list_analysis<S>() -> impl IntoResponse { "stub" }
|
||||
pub async fn get_analysis<S>() -> impl IntoResponse { "stub" }
|
||||
```
|
||||
|
||||
```bash
|
||||
cargo check -p erp-ai
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add crates/erp-ai/src/
|
||||
git commit -m "feat(ai): AiState + AiModule (ErpModule impl + 权限 + 路由骨架)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 10: erp-server 集成 — Config + State + 路由注册
|
||||
|
||||
**Files:**
|
||||
- Modify: `crates/erp-server/src/config.rs` — 添加 AiConfig
|
||||
- Modify: `crates/erp-server/src/state.rs` — 添加 FromRef<AiState>
|
||||
- Modify: `crates/erp-server/src/main.rs` — 注册模块 + 合并路由
|
||||
- Modify: `crates/erp-server/Cargo.toml` — 添加 erp-ai 依赖
|
||||
- Modify: `crates/erp-server/config/default.toml` — 添加 [ai] 段
|
||||
|
||||
- [ ] **Step 1: erp-server/Cargo.toml 添加 erp-ai**
|
||||
|
||||
```toml
|
||||
erp-ai.workspace = true
|
||||
```
|
||||
|
||||
- [ ] **Step 2: config.rs 添加 AiConfig**
|
||||
|
||||
```rust
|
||||
// 在 AppConfig 结构体中添加:
|
||||
pub ai: AiConfig,
|
||||
|
||||
// 新增结构体:
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct AiConfig {
|
||||
pub default_provider: String,
|
||||
pub api_key: String,
|
||||
pub base_url: Option<String>,
|
||||
pub model: String,
|
||||
pub max_tokens: u32,
|
||||
pub temperature: f32,
|
||||
pub cache_ttl_seconds: u64,
|
||||
pub rate_limit_patient_daily: u32,
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: config/default.toml 添加 [ai] 段**
|
||||
|
||||
```toml
|
||||
[ai]
|
||||
default_provider = "claude"
|
||||
api_key = ""
|
||||
base_url = "https://api.anthropic.com"
|
||||
model = "claude-sonnet-4-6"
|
||||
max_tokens = 2048
|
||||
temperature = 0.3
|
||||
cache_ttl_seconds = 604800
|
||||
rate_limit_patient_daily = 10
|
||||
```
|
||||
|
||||
- [ ] **Step 4: state.rs 添加 FromRef**
|
||||
|
||||
```rust
|
||||
impl FromRef<AppState> for erp_ai::AiState {
|
||||
fn from_ref(state: &AppState) -> Self {
|
||||
// 从 config 构建 ClaudeProvider
|
||||
let provider = erp_ai::provider::claude::ClaudeProvider::new(
|
||||
state.config.ai.api_key.clone(),
|
||||
);
|
||||
let db = state.db.clone();
|
||||
let event_bus = state.event_bus.clone();
|
||||
|
||||
let analysis = std::sync::Arc::new(
|
||||
erp_ai::service::analysis::AnalysisService::new(
|
||||
Box::new(provider), db.clone(),
|
||||
)
|
||||
);
|
||||
let prompt = std::sync::Arc::new(
|
||||
erp_ai::service::prompt::PromptService::new(db.clone())
|
||||
);
|
||||
let usage = std::sync::Arc::new(
|
||||
erp_ai::service::usage::UsageService::new(db.clone())
|
||||
);
|
||||
|
||||
Self { db, event_bus, analysis, prompt, usage }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 5: main.rs 注册模块 + 路由**
|
||||
|
||||
```rust
|
||||
// 1. 创建 AiModule
|
||||
let ai_module = erp_ai::AiModule;
|
||||
|
||||
// 2. 注册到 registry
|
||||
let registry = ModuleRegistry::new()
|
||||
.register(auth_module)
|
||||
// ...existing...
|
||||
.register(ai_module);
|
||||
|
||||
// 3. 合并路由 (protected_routes 中)
|
||||
.merge(erp_ai::AiModule::protected_routes())
|
||||
```
|
||||
|
||||
- [ ] **Step 6: 验证全 workspace 编译**
|
||||
|
||||
```bash
|
||||
cargo check --workspace
|
||||
```
|
||||
|
||||
- [ ] **Step 7: 提交**
|
||||
|
||||
```bash
|
||||
git add crates/erp-server/
|
||||
git commit -m "feat(server): erp-ai 模块集成 — Config/State/路由注册"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user