ai_scheduler/internal/data/mongo_model/advicer_client.go

168 lines
7.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 "客户信息"
}