package mongo_model import ( "encoding/json" "strings" "time" ) // 画像动态栏目约定键(后端按栏目名读取,销售在新编辑器中以同名栏目维护) const ( SectionKeyClientName = "姓名" SectionKeyBirthday = "生日" ) // 客户等级 const ( ClientLevelUnknown = "" // 未评估 ClientLevelRegular = "regular" // 熟客:已成交/高频互动,AI 尽量不介入,人工接管 ClientLevelIntent = "intent" // 意向客户:主动跟踪、下单邀约、活动推送 ClientLevelSleeping = "sleeping" // 沉睡客户:只推活动并尝试邀约 ClientLevelNon = "non" // 非客户:AI 不参与回复 ) // ClientLevelDesc 客户等级中文描述 type ClientLevelDescMap map[string]string var ClientLevelDesc = ClientLevelDescMap{ ClientLevelUnknown: "未评估", ClientLevelRegular: "熟客", ClientLevelIntent: "意向客户", ClientLevelSleeping: "沉睡客户", ClientLevelNon: "非客户", } type AdvicerClientMongo struct { ProjectId int32 `json:"projectId" bson:"projectId"` AdvicerId int32 `json:"advicerId" bson:"advicerId"` Wxid string `json:"wxid" bson:"wxid"` // 客户微信 wxid(回调唯一标识) AppId string `json:"appId" bson:"appId"` // 绑定的登录实例 appId ClientLevel string `json:"clientLevel" bson:"clientLevel"` // 客户等级:regular/intent/sleeping/non Mission string `json:"mission" bson:"mission"` // 当前对话任务(由对话 AI 回传并回写,展示在客户列表) LevelReason string `json:"levelReason" bson:"levelReason"` // 等级判定理由(评估产出) LevelUpdateAt time.Time `json:"levelUpdateAt" bson:"levelUpdateAt"` // 等级最后评估时间 LastContactAt time.Time `json:"lastContactAt" bson:"lastContactAt"` // 最后互动时间(任意方向) LastClientMsgAt time.Time `json:"lastClientMsgAt" bson:"lastClientMsgAt"` // 最后客户消息时间 LastReplyAt time.Time `json:"lastReplyAt" bson:"lastReplyAt"` // 最后回复客户时间 MsgCount int `json:"msgCount" bson:"msgCount"` // 累计互动消息数 AiEnabled bool `json:"aiEnabled" bson:"aiEnabled"` // 是否允许 AI 参与对话 LastIterateAt time.Time `json:"lastIterateAt" bson:"lastIterateAt"` // Profile 客户画像动态栏目(栏目名 → 内容,内容为 string/[]interface{}/map,与 advicer_project_data 同构) Profile map[string]interface{} `json:"profile" bson:"profile"` LastUpdateTime time.Time `json:"lastUpdateTime" bson:"lastUpdateTime"` } func NewAdvicerClientMongo() *AdvicerClientMongo { return &AdvicerClientMongo{} } func (a *AdvicerClientMongo) MongoTableName() string { return "advicer_client" } // AdvicerClientMongoEntity 客户画像的统一表示:动态栏目 map(栏目名 → 内容)。 // 采用类型别名,使既有消费点(JSON 序列化注入 prompt / ChatData)无需改动。 type AdvicerClientMongoEntity = map[string]interface{} // Entity 返回画像栏目(供 AI 注入与提示词拼装);nil 时返回空 map。 func (a *AdvicerClientMongo) Entity() AdvicerClientMongoEntity { if a.Profile == nil { return AdvicerClientMongoEntity{} } return a.Profile } // SectionValue 按栏目名读取栏目内容:先精确匹配,再做去空格/包含式模糊匹配。 func (a *AdvicerClientMongo) SectionValue(name string) interface{} { name = strings.TrimSpace(name) if a.Profile == nil || name == "" { return nil } if v, ok := a.Profile[name]; ok { return v } for k, v := range a.Profile { key := strings.TrimSpace(k) if key == "" { continue } if strings.Contains(key, name) || strings.Contains(name, key) { return v } } return nil } // SectionString 按栏目名读取字符串值;非字符串值返回其 JSON 串(供展示)。 func (a *AdvicerClientMongo) SectionString(name string) string { v := a.SectionValue(name) if v == nil { return "" } switch x := v.(type) { case string: return strings.TrimSpace(x) default: if b, e := json.Marshal(x); e == nil { return string(b) } return "" } } // Customer 客户信息 type Customer []ClientInfo type ClientInfo struct { // 个人信息 PersonalInfo PersonalInfo `json:"personalInfo"` // 购房目的 PurchasePurpose PurchasePurpose `json:"purchasePurpose"` // 核心需求 CoreDemands CoreDemands `json:"coreDemands"` // 关注点与顾虑 Concerns []string `json:"concerns"` // 决策建议 DecisionProfile []string `json:"decisionProfile"` } type PersonalInfo struct { Name string `json:"name"` // 姓氏 Gender string `json:"gender"` // 性别 Location string `json:"location"` // 来源地/当前居住地 IsFirstHome bool `json:"isFirstHome"` // 是否首套房 FamilyOrganize string `json:"familyOrganize"` // 家庭人数 Birthday string `json:"birthday"` // 生日(如 05-20 或 1995-05-20,用于 AI 主动祝福) } type PurchasePurpose struct { PrimaryPurpose string `json:"primaryPurpose"` // 主要目的 SecondaryPurpose string `json:"secondaryPurpose"` // 次要目的 DecisionMakers string `json:"decisionMakers"` // 决策人 } type CoreDemands struct { TotalBudget string `json:"totalBudget"` // 预算范围 PreferredLayout string `json:"preferredLayout"` // 偏好户型 CoreAppeal string `json:"coreAppeal"` // 核心述求 } func (e *Customer) Example() string { return `[{"personalInfo":{"name":"唐","gender":"男","location":"成都北门","isFirstHome":true,"familyOrganize":"夫妻"},"purchasePurpose":{"primaryPurpose":"首次置业,解决自住","secondaryPurpose":"资产保值,未来可出租","decisionMakers":"夫妻双方"},"coreDemands":{"totalBudget":"350-400"","preferredLayout":"118㎡四房三卫双套房","coreAppeal":"在有限预算内满足家庭居住功能,确保房产保值"},"concerns":["总价超预算风险","板块保值能力"],"decisionProfile":["预算导向,严格控制总价","重点关注户型功能性和实用性"]},{"personalInfo":{"name":"冯女士","gender":"女","location":"","isFirstHome":false,"familyOrganize":"夫妻+1孩+父母同住"},"purchasePurpose":{"primaryPurpose":"改善居住条件","secondaryPurpose":"子女教育质量提升","decisionMakers":"夫妻双方需家庭共同商议]},"coreDemands":{"totalBudget":"400-500","preferredLayout":"118㎡四房三卫(非全景户型)","coreAppeal":"安静舒适、学区有保障的改善型住房"},"concerns":["临路噪音影响老人休息","学区质量和稳定性","社区小,绿化空间有限","得房率是否足够","二八板块学区对比"],"decisionProfile":["对噪音敏感,需要安静环境","重视教育资源配置","关注社区品质和舒适度","需要详细对比不同板块学区优势"]}]` } func (e *Customer) Copy() AdviceData { return new(Customer) } func (e *Customer) Role() AdviceRole { return RoleClient } func (e *Customer) Desc() string { return "客户信息" }