274 lines
7.9 KiB
Rust
274 lines
7.9 KiB
Rust
//! AI模型集成层
|
||
//!
|
||
//! 提供对ChatGPT、DeepSeek、豆包AI的统一接口
|
||
|
||
use rust_decimal::Decimal;
|
||
use serde::{Deserialize, Serialize};
|
||
use anyhow::Result;
|
||
use chrono::{DateTime, Utc};
|
||
|
||
use crate::{Asset, Jurisdiction, InternationalAgreement};
|
||
|
||
/// AI服务提供商
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||
pub enum AIProvider {
|
||
/// OpenAI ChatGPT-4.1
|
||
ChatGPT,
|
||
/// DeepSeek-V3
|
||
DeepSeek,
|
||
/// 字节豆包AI-Pro
|
||
DouBao,
|
||
}
|
||
|
||
/// AI估值结果
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct AIValuationResult {
|
||
/// AI提供商
|
||
pub provider: AIProvider,
|
||
/// 估值(XTZH)
|
||
pub valuation_xtzh: Decimal,
|
||
/// 置信度 [0.0, 1.0]
|
||
pub confidence: f64,
|
||
/// 推理过程
|
||
pub reasoning: String,
|
||
/// 时间戳
|
||
pub timestamp: DateTime<Utc>,
|
||
}
|
||
|
||
/// AI模型管理器
|
||
pub struct AIModelManager {
|
||
chatgpt_api_key: String,
|
||
deepseek_api_key: String,
|
||
doubao_api_key: String,
|
||
}
|
||
|
||
impl AIModelManager {
|
||
/// 创建新的AI模型管理器
|
||
pub fn new(
|
||
chatgpt_api_key: String,
|
||
deepseek_api_key: String,
|
||
doubao_api_key: String,
|
||
) -> Result<Self> {
|
||
Ok(Self {
|
||
chatgpt_api_key,
|
||
deepseek_api_key,
|
||
doubao_api_key,
|
||
})
|
||
}
|
||
|
||
/// 并行调用所有AI模型进行估值
|
||
pub async fn appraise_all(
|
||
&self,
|
||
asset: &Asset,
|
||
jurisdiction: Jurisdiction,
|
||
agreement: InternationalAgreement,
|
||
xtzh_price_usd: Decimal,
|
||
) -> Result<Vec<AIValuationResult>> {
|
||
// 使用tokio::join!并行调用
|
||
let (chatgpt_result, deepseek_result, doubao_result) = tokio::join!(
|
||
self.appraise_with_chatgpt(asset, jurisdiction, agreement, xtzh_price_usd),
|
||
self.appraise_with_deepseek(asset, jurisdiction, agreement, xtzh_price_usd),
|
||
self.appraise_with_doubao(asset, jurisdiction, agreement, xtzh_price_usd),
|
||
);
|
||
|
||
let mut results = Vec::new();
|
||
|
||
if let Ok(result) = chatgpt_result {
|
||
results.push(result);
|
||
} else {
|
||
log::warn!("ChatGPT估值失败: {:?}", chatgpt_result.err());
|
||
}
|
||
|
||
if let Ok(result) = deepseek_result {
|
||
results.push(result);
|
||
} else {
|
||
log::warn!("DeepSeek估值失败: {:?}", deepseek_result.err());
|
||
}
|
||
|
||
if let Ok(result) = doubao_result {
|
||
results.push(result);
|
||
} else {
|
||
log::warn!("豆包AI估值失败: {:?}", doubao_result.err());
|
||
}
|
||
|
||
if results.is_empty() {
|
||
anyhow::bail!("所有AI模型估值均失败");
|
||
}
|
||
|
||
Ok(results)
|
||
}
|
||
|
||
/// 使用ChatGPT进行估值
|
||
async fn appraise_with_chatgpt(
|
||
&self,
|
||
asset: &Asset,
|
||
jurisdiction: Jurisdiction,
|
||
agreement: InternationalAgreement,
|
||
xtzh_price_usd: Decimal,
|
||
) -> Result<AIValuationResult> {
|
||
let prompt = self.build_valuation_prompt(asset, jurisdiction, agreement, xtzh_price_usd);
|
||
|
||
// TODO: 实际调用ChatGPT API
|
||
// 这里暂时返回模拟数据
|
||
log::info!("调用ChatGPT API进行估值... (API Key: {}...)",
|
||
&self.chatgpt_api_key.chars().take(10).collect::<String>());
|
||
|
||
Ok(AIValuationResult {
|
||
provider: AIProvider::ChatGPT,
|
||
valuation_xtzh: asset.base_valuation_local / xtzh_price_usd,
|
||
confidence: 0.85,
|
||
reasoning: format!("ChatGPT估值推理: {}", prompt),
|
||
timestamp: Utc::now(),
|
||
})
|
||
}
|
||
|
||
/// 使用DeepSeek进行估值
|
||
async fn appraise_with_deepseek(
|
||
&self,
|
||
asset: &Asset,
|
||
jurisdiction: Jurisdiction,
|
||
agreement: InternationalAgreement,
|
||
xtzh_price_usd: Decimal,
|
||
) -> Result<AIValuationResult> {
|
||
let prompt = self.build_valuation_prompt(asset, jurisdiction, agreement, xtzh_price_usd);
|
||
|
||
// TODO: 实际调用DeepSeek API
|
||
log::info!("调用DeepSeek API进行估值... (API Key: {}...)",
|
||
&self.deepseek_api_key.chars().take(10).collect::<String>());
|
||
|
||
Ok(AIValuationResult {
|
||
provider: AIProvider::DeepSeek,
|
||
valuation_xtzh: asset.base_valuation_local / xtzh_price_usd * Decimal::new(105, 2), // 1.05倍
|
||
confidence: 0.88,
|
||
reasoning: format!("DeepSeek估值推理: {}", prompt),
|
||
timestamp: Utc::now(),
|
||
})
|
||
}
|
||
|
||
/// 使用豆包AI进行估值
|
||
async fn appraise_with_doubao(
|
||
&self,
|
||
asset: &Asset,
|
||
jurisdiction: Jurisdiction,
|
||
agreement: InternationalAgreement,
|
||
xtzh_price_usd: Decimal,
|
||
) -> Result<AIValuationResult> {
|
||
let prompt = self.build_valuation_prompt(asset, jurisdiction, agreement, xtzh_price_usd);
|
||
|
||
// TODO: 实际调用豆包AI API
|
||
log::info!("调用豆包AI API进行估值... (API Key: {}...)",
|
||
&self.doubao_api_key.chars().take(10).collect::<String>());
|
||
|
||
Ok(AIValuationResult {
|
||
provider: AIProvider::DouBao,
|
||
valuation_xtzh: asset.base_valuation_local / xtzh_price_usd * Decimal::new(98, 2), // 0.98倍
|
||
confidence: 0.82,
|
||
reasoning: format!("豆包AI估值推理: {}", prompt),
|
||
timestamp: Utc::now(),
|
||
})
|
||
}
|
||
|
||
/// 构建估值提示词
|
||
fn build_valuation_prompt(
|
||
&self,
|
||
asset: &Asset,
|
||
jurisdiction: Jurisdiction,
|
||
agreement: InternationalAgreement,
|
||
xtzh_price_usd: Decimal,
|
||
) -> String {
|
||
let jurisdiction_info = jurisdiction.info();
|
||
|
||
format!(
|
||
r#"# NAC资产估值任务
|
||
|
||
## 资产信息
|
||
- ID: {}
|
||
- 类型: {:?}
|
||
- GNACS编码: {}
|
||
- 名称: {}
|
||
- 基础估值: {} {}
|
||
|
||
## 辖区信息
|
||
- 辖区: {:?}
|
||
- 会计准则: {:?}
|
||
- 法系: {:?}
|
||
- 企业所得税率: {:.1}%
|
||
- 资本利得税率: {:.1}%
|
||
- 增值税率: {:.1}%
|
||
- 监管成本率: {:.1}%
|
||
- 基础流动性折扣: {:.1}%
|
||
|
||
## 国际贸易协定
|
||
- 协定: {:?}
|
||
|
||
## XTZH价格
|
||
- 当前价格: {} USD
|
||
|
||
## 估值要求
|
||
1. 根据资产类型、辖区特性、国际协定进行综合估值
|
||
2. 考虑税收、监管成本、流动性折扣等因素
|
||
3. 输出估值结果(XTZH)和置信度(0-1)
|
||
4. 提供详细的推理过程
|
||
|
||
请以JSON格式输出:
|
||
{{
|
||
"valuation_xtzh": <数值>,
|
||
"confidence": <0-1>,
|
||
"reasoning": "<详细推理过程>"
|
||
}}
|
||
"#,
|
||
asset.id,
|
||
asset.asset_type,
|
||
asset.gnacs_code,
|
||
asset.name,
|
||
asset.base_valuation_local,
|
||
asset.local_currency,
|
||
jurisdiction,
|
||
jurisdiction_info.accounting_standard,
|
||
jurisdiction_info.legal_system,
|
||
jurisdiction_info.corporate_tax_rate * 100.0,
|
||
jurisdiction_info.capital_gains_tax_rate * 100.0,
|
||
jurisdiction_info.vat_rate * 100.0,
|
||
jurisdiction_info.regulatory_cost_rate * 100.0,
|
||
jurisdiction_info.base_liquidity_discount * 100.0,
|
||
agreement,
|
||
xtzh_price_usd,
|
||
)
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
use crate::AssetType;
|
||
|
||
#[test]
|
||
fn test_build_valuation_prompt() {
|
||
let manager = AIModelManager::new(
|
||
"test_key1".to_string(),
|
||
"test_key2".to_string(),
|
||
"test_key3".to_string(),
|
||
).expect("mainnet: handle error");
|
||
|
||
let asset = Asset::new(
|
||
"test_001".to_string(),
|
||
AssetType::RealEstate,
|
||
"GNACS-001".to_string(),
|
||
"Test Property".to_string(),
|
||
Decimal::new(1000000, 0),
|
||
"USD".to_string(),
|
||
);
|
||
|
||
let prompt = manager.build_valuation_prompt(
|
||
&asset,
|
||
Jurisdiction::US,
|
||
InternationalAgreement::WTO,
|
||
Decimal::new(100, 0),
|
||
);
|
||
|
||
assert!(prompt.contains("NAC资产估值任务"));
|
||
assert!(prompt.contains("Test Property"));
|
||
assert!(prompt.contains("US"));
|
||
}
|
||
}
|