fix(growth): MEDIUM-12 ProfileUpdater 补齐 5 维度画像更新
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
根因: ProfileUpdater 只处理 industry 和 communication_style 2/5 维度, 跳过 recent_topic、pain_point、preferred_tool。 修复: - ProfileFieldUpdate 添加 kind 字段 (SetField | AppendArray) - collect_updates() 现在处理全部 5 个维度: - industry, communication_style → SetField (直接覆盖) - recent_topic, pain_point, preferred_tool → AppendArray (追加去重) - growth.rs 根据 ProfileUpdateKind 分派到不同的 UserProfileStore 方法: - SetField → update_field() - AppendArray → add_recent_topic() / add_pain_point() / add_preferred_tool() - ProfileUpdateKind re-exported from lib.rs 测试: test_collect_updates_all_five_dimensions 验证 5 个维度 + 2 种更新类型
This commit is contained in:
@@ -4,11 +4,21 @@
|
||||
|
||||
use crate::types::CombinedExtraction;
|
||||
|
||||
/// 更新类型:字段覆盖 vs 数组追加
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ProfileUpdateKind {
|
||||
/// 直接覆盖字段值(industry, communication_style)
|
||||
SetField,
|
||||
/// 追加到 JSON 数组字段(recent_topic, pain_point, preferred_tool)
|
||||
AppendArray,
|
||||
}
|
||||
|
||||
/// 待更新的画像字段
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ProfileFieldUpdate {
|
||||
pub field: String,
|
||||
pub value: String,
|
||||
pub kind: ProfileUpdateKind,
|
||||
}
|
||||
|
||||
/// 用户画像更新器
|
||||
@@ -22,11 +32,7 @@ impl UserProfileUpdater {
|
||||
}
|
||||
|
||||
/// 从提取结果中收集需要更新的画像字段
|
||||
/// 返回 (field, value) 列表,由调用方负责实际的异步写入
|
||||
///
|
||||
/// 注意:只收集 UserProfileStore::update_field() 支持的字段。
|
||||
/// ProfileSignals 中的 recent_topic / pain_point / preferred_tool
|
||||
/// 需要 update_field 扩展后才能写入,当前跳过。
|
||||
/// 返回 (field, value, kind) 列表,由调用方根据 kind 选择写入方式
|
||||
pub fn collect_updates(
|
||||
&self,
|
||||
extraction: &CombinedExtraction,
|
||||
@@ -38,6 +44,7 @@ impl UserProfileUpdater {
|
||||
updates.push(ProfileFieldUpdate {
|
||||
field: "industry".to_string(),
|
||||
value: industry.clone(),
|
||||
kind: ProfileUpdateKind::SetField,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -45,6 +52,31 @@ impl UserProfileUpdater {
|
||||
updates.push(ProfileFieldUpdate {
|
||||
field: "communication_style".to_string(),
|
||||
value: style.clone(),
|
||||
kind: ProfileUpdateKind::SetField,
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(ref topic) = signals.recent_topic {
|
||||
updates.push(ProfileFieldUpdate {
|
||||
field: "recent_topic".to_string(),
|
||||
value: topic.clone(),
|
||||
kind: ProfileUpdateKind::AppendArray,
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(ref pain) = signals.pain_point {
|
||||
updates.push(ProfileFieldUpdate {
|
||||
field: "pain_point".to_string(),
|
||||
value: pain.clone(),
|
||||
kind: ProfileUpdateKind::AppendArray,
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(ref tool) = signals.preferred_tool {
|
||||
updates.push(ProfileFieldUpdate {
|
||||
field: "preferred_tool".to_string(),
|
||||
value: tool.clone(),
|
||||
kind: ProfileUpdateKind::AppendArray,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,6 +105,7 @@ mod tests {
|
||||
assert_eq!(updates.len(), 1);
|
||||
assert_eq!(updates[0].field, "industry");
|
||||
assert_eq!(updates[0].value, "healthcare");
|
||||
assert_eq!(updates[0].kind, ProfileUpdateKind::SetField);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -94,4 +127,31 @@ mod tests {
|
||||
|
||||
assert_eq!(updates.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_collect_updates_all_five_dimensions() {
|
||||
let mut extraction = CombinedExtraction::default();
|
||||
extraction.profile_signals.industry = Some("healthcare".to_string());
|
||||
extraction.profile_signals.communication_style = Some("concise".to_string());
|
||||
extraction.profile_signals.recent_topic = Some("报表自动化".to_string());
|
||||
extraction.profile_signals.pain_point = Some("手动汇总太慢".to_string());
|
||||
extraction.profile_signals.preferred_tool = Some("researcher".to_string());
|
||||
|
||||
let updater = UserProfileUpdater::new();
|
||||
let updates = updater.collect_updates(&extraction);
|
||||
|
||||
assert_eq!(updates.len(), 5);
|
||||
let set_fields: Vec<_> = updates
|
||||
.iter()
|
||||
.filter(|u| u.kind == ProfileUpdateKind::SetField)
|
||||
.map(|u| u.field.as_str())
|
||||
.collect();
|
||||
let append_fields: Vec<_> = updates
|
||||
.iter()
|
||||
.filter(|u| u.kind == ProfileUpdateKind::AppendArray)
|
||||
.map(|u| u.field.as_str())
|
||||
.collect();
|
||||
assert_eq!(set_fields, vec!["industry", "communication_style"]);
|
||||
assert_eq!(append_fields, vec!["recent_topic", "pain_point", "preferred_tool"]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user