123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- package crontask
- import (
- "encoding/json"
- "fmt"
- "github.com/google/uuid"
- "github.com/zeromicro/go-zero/core/logx"
- "strconv"
- "strings"
- "time"
- "wechat-api/ent/contact"
- "wechat-api/ent/contactfield"
- "wechat-api/ent/contactfieldtemplate"
- "wechat-api/ent/custom_types"
- "wechat-api/ent/predicate"
- "wechat-api/ent/usagedetail"
- "wechat-api/internal/types"
- "wechat-api/internal/utils/compapi"
- )
- type ResponseItem struct {
- DataIndex string `json:"dataIndex"`
- Value []string `json:"value"`
- }
- type FieldPropsOptions struct {
- Label string `json:"label"`
- Value string `json:"value"`
- }
- type FieldProps struct {
- Options []FieldPropsOptions `json:"options"`
- }
- type FormData struct {
- Title string `json:"title"`
- DataIndex string `json:"dataIndex"`
- ValueType string `json:"valueType"`
- FieldProps FieldProps `json:"fieldProps"`
- }
- func (l *CronTask) analyze() {
- usageDetails := make(map[string]map[string]string)
- contactFieldTemplates := make(map[string][]custom_types.ContactFieldTemplate)
- template_type_text := "text"
- template_type_radio := "radio"
- //template_type_date := "date"
- template_sex_id := "sex"
- template_sex_label := "性别"
- template_sex_options_man_label := "男"
- template_sex_options_man_value := "男"
- template_sex_options_woman_label := "女"
- template_sex_options_woman_value := "男"
- template_phone_id := "phone"
- template_phone_label := "手机号"
- //template_name_id := "name"
- //template_name_label := "姓名"
- //
- //template_age_id := "age"
- //template_age_label := "年龄(以字符串形式返回阿拉伯数字)"
- //
- //template_area_id := "area"
- //template_area_label := "地区"
- //
- //template_birthday_id := "birthday"
- //template_birthday_label := "出生日期"
- //
- //template_birtharea_id := "birtharea"
- //template_birtharea_label := "出生地"
- //
- //template_idcard_no_id := "idcard_no"
- //template_idcard_no_label := "身份证号"
- //
- //template_title_id := "title"
- //template_title_label := "称呼"
- contactBasicFieldTemplates := []custom_types.ContactFieldTemplate{
- {
- Label: &template_sex_label,
- Id: &template_sex_id,
- Type: &template_type_radio,
- Options: []custom_types.ContactFieldTemplateOptions{
- {
- Label: &template_sex_options_man_label,
- Value: &template_sex_options_man_value,
- }, {
- Label: &template_sex_options_woman_label,
- Value: &template_sex_options_woman_value,
- },
- },
- },
- {
- Label: &template_phone_label,
- Id: &template_phone_id,
- Type: &template_type_text,
- },
- //{
- // Label: &template_name_label,
- // Id: &template_name_id,
- // Type: &template_type_text,
- //}, {
- // Label: &template_age_label,
- // Id: &template_age_id,
- // Type: &template_type_text,
- //}, {
- // Label: &template_area_label,
- // Id: &template_area_id,
- // Type: &template_type_text,
- //}, {
- // Label: &template_birthday_label,
- // Id: &template_birthday_id,
- // Type: &template_type_date,
- //}, {
- // Label: &template_birtharea_label,
- // Id: &template_birtharea_id,
- // Type: &template_type_text,
- //}, {
- // Label: &template_idcard_no_label,
- // Id: &template_idcard_no_id,
- // Type: &template_type_text,
- //}, {
- // Label: &template_title_label,
- // Id: &template_title_id,
- // Type: &template_type_text,
- //},
- }
- var predicates []predicate.UsageDetail
- predicates = append(predicates, usagedetail.TypeIn(1, 3, 4, 6))
- predicates = append(predicates, usagedetail.AppIn(1, 3, 4, 5))
- //yesterdayStart := time.Now().AddDate(0, 0, -1).Truncate(24 * time.Hour)
- //yesterdayEnd := yesterdayStart.Add(24 * time.Hour)
- //loc, _ := time.LoadLocation("Asia/Shanghai")
- //now := time.Now().In(loc)
- //yesterdayEnd := now.Truncate(24 * time.Hour)
- //yesterdayStart := yesterdayEnd.AddDate(0, 0, -1)
- //predicates = append(predicates, usagedetail.CreatedAtGTE(yesterdayStart))
- //predicates = append(predicates, usagedetail.CreatedAtLT(yesterdayEnd))
- todayStart := time.Now().AddDate(0, 0, 0).Truncate(24 * time.Hour)
- todayEnd := todayStart.Add(24 * time.Hour)
- predicates = append(predicates, usagedetail.CreatedAtGTE(todayStart))
- predicates = append(predicates, usagedetail.CreatedAtLT(todayEnd))
- data, err := l.svcCtx.DB.UsageDetail.Query().Where(predicates...).All(l.ctx)
- logx.Info("usageDetails: ", data)
- if err != nil {
- return
- }
- wxs, err := l.svcCtx.DB.Wx.Query().All(l.ctx)
- if err != nil {
- return
- }
- for _, wx := range wxs {
- c, _ := l.svcCtx.DB.ContactFieldTemplate.Query().Where(contactfieldtemplate.OrganizationID(wx.OrganizationID)).First(l.ctx)
- if c != nil {
- contactFieldTemplates[wx.Wxid] = c.Template
- } else {
- contactFieldTemplates[wx.Wxid] = nil
- }
- }
- for _, u := range data {
- if contactFieldTemplates[u.BotID] == nil {
- continue
- }
- if _, ok := usageDetails[u.BotID]; !ok {
- usageDetails[u.BotID] = make(map[string]string)
- }
- usageDetails[u.BotID][u.ReceiverID] += fmt.Sprintf("用户:%s\n机器人:%s\n", u.Request, u.Response)
- }
- logx.Info("usageDetails: ", usageDetails)
- for botID, template := range contactFieldTemplates {
- if template == nil {
- template = contactBasicFieldTemplates
- } else {
- template = append(template, contactBasicFieldTemplates...)
- }
- for receiverID, messages := range usageDetails[botID] {
- result, _ := l.openaiRequest(messages, template)
- logx.Info("result: ", result)
- if result == nil {
- continue
- }
- _ = l.UpdateContactFields(botID, receiverID, result)
- }
- }
- }
- func (l *CronTask) openaiRequest(messages string, template []custom_types.ContactFieldTemplate) ([]ResponseItem, error) {
- formData := ConvertFormData(template)
- jsonBytes, err := json.Marshal(formData)
- if err != nil {
- return nil, err
- }
- jsonStr := string(jsonBytes)
- logx.Info("contactFieldTemplates: ", jsonStr)
- req := &types.CompApiReq{
- types.CompCtlReq{
- "form",
- "",
- false,
- "",
- },
- types.StdCompApiReq{
- "gpt-4o",
- []types.StdCompMessage{},
- false,
- nil,
- },
- types.FastGptSpecReq{
- "",
- "",
- "",
- false,
- map[string]string{
- "form_data": jsonStr,
- "chat_history": messages,
- "external_id": uuid.New().String(),
- },
- },
- }
- resp, err := compapi.NewClient(l.ctx, compapi.WithApiBase("http://new-api.gkscrm.com/v1/"),
- compapi.WithApiKey("sk-wwttAtdLcTfeF7F2Eb9d3592Bd4c487f8e8fA544D6C4BbA9")).
- Chat(req)
- logx.Info("resp: ", resp)
- if err == nil && resp != nil && len(resp.Choices) > 0 {
- logx.Info("resp.Choices: ", resp.Choices[0].Message.Content)
- // 尝试第一层解析成 string
- items, err := parseContent(resp.Choices[0].Message.Content)
- if err != nil {
- return nil, err
- }
- return items, nil
- } else if resp != nil && len(resp.Choices) == 0 {
- return nil, err
- }
- //url := "https://toolsapi-debug.gkscrm.com/call_center/form/extract"
- //bodyData := map[string]interface{}{
- // "form_data": ConvertFormData(template),
- // "chat_history": messages,
- // "external_id": uuid.New().String(),
- //}
- //logx.Info("bodyData: %+v", bodyData)
- //bodyBytes, err := json.Marshal(bodyData)
- //if err != nil {
- // return nil, err
- //}
- //
- //req, err := http.NewRequest("POST", url, bytes.NewBuffer(bodyBytes))
- //if err != nil {
- // return nil, err
- //}
- //req.Header.Set("Content-Type", "application/json")
- //req.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIn0.ZS9jnsLPCnmc8L_lu4yaQFp34vwWF1mHlHSBYrY5JVs")
- //
- //client := &http.Client{}
- //resp, err := client.Do(req)
- //if err != nil || resp == nil || resp.Body == nil {
- // logx.Error("read body error: ", err)
- // return nil, err
- //}
- //
- //logx.Info("err: ", err)
- //if err != nil {
- // return nil, err
- //}
- //defer resp.Body.Close()
- //
- //if resp.StatusCode != http.StatusOK {
- // return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
- //}
- //
- ////var result []ResponseItem
- //var fullResp struct {
- // Data []ResponseItem `json:"data"`
- //}
- //err = json.NewDecoder(resp.Body).Decode(&fullResp)
- //if err != nil {
- // return nil, err
- //}
- //
- //return fullResp.Data, nil
- return nil, err
- }
- func (l *CronTask) UpdateContactFields(botID string, receiverID string, fields []ResponseItem) error {
- basic_ids := []string{"sex", "phone", "name", "age", "area", "birthday", "birtharea", "idcard_no", "title"}
- c, _ := l.svcCtx.DB.Contact.Query().Where(contact.WxWxidEQ(botID), contact.WxidEQ(receiverID)).First(l.ctx)
- if c == nil {
- return fmt.Errorf("Contact not find")
- }
- for _, field := range fields {
- if contains(basic_ids, field.DataIndex) {
- if len(field.Value) == 0 {
- continue
- }
- value := 0
- if field.DataIndex == "sex" && c.Sex == 0 {
- if field.Value[0] == "男" {
- value = 1
- } else if field.Value[0] == "女" {
- value = 2
- }
- _, err := l.svcCtx.DB.Contact.Update().
- Where(contact.WxWxidEQ(botID), contact.WxidEQ(receiverID)).
- SetSex(value).
- Save(l.ctx)
- if err != nil {
- continue
- }
- } else if field.DataIndex == "phone" && c.Phone == "" {
- _, err := l.svcCtx.DB.Contact.Update().
- Where(contact.WxWxidEQ(botID), contact.WxidEQ(receiverID)).
- SetPhone(field.Value[0]).
- Save(l.ctx)
- if err != nil {
- continue
- }
- } else if field.DataIndex == "name" && c.Cname == "" {
- _, err := l.svcCtx.DB.Contact.Update().
- Where(contact.WxWxidEQ(botID), contact.WxidEQ(receiverID)).
- SetCname(field.Value[0]).
- Save(l.ctx)
- if err != nil {
- continue
- }
- } else if field.DataIndex == "age" && c.Cage == 0 {
- num, err := strconv.Atoi(field.Value[0])
- if err != nil {
- continue
- }
- _, err = l.svcCtx.DB.Contact.Update().
- Where(contact.WxWxidEQ(botID), contact.WxidEQ(receiverID)).
- SetCage(num).
- Save(l.ctx)
- if err != nil {
- continue
- }
- } else if field.DataIndex == "area" && c.Carea == "" {
- _, err := l.svcCtx.DB.Contact.Update().
- Where(contact.WxWxidEQ(botID), contact.WxidEQ(receiverID)).
- SetCarea(field.Value[0]).
- Save(l.ctx)
- if err != nil {
- continue
- }
- } else if field.DataIndex == "birthday" && c.Cbirthday == "" {
- _, err := l.svcCtx.DB.Contact.Update().
- Where(contact.WxWxidEQ(botID), contact.WxidEQ(receiverID)).
- SetCbirthday(field.Value[0]).
- Save(l.ctx)
- if err != nil {
- continue
- }
- } else if field.DataIndex == "birtharea" && c.Cbirtharea == "" {
- _, err := l.svcCtx.DB.Contact.Update().
- Where(contact.WxWxidEQ(botID), contact.WxidEQ(receiverID)).
- SetCbirtharea(field.Value[0]).
- Save(l.ctx)
- if err != nil {
- continue
- }
- } else if field.DataIndex == "idcard_no" && c.CidcardNo == "" {
- _, err := l.svcCtx.DB.Contact.Update().
- Where(contact.WxWxidEQ(botID), contact.WxidEQ(receiverID)).
- SetCidcardNo(field.Value[0]).
- Save(l.ctx)
- if err != nil {
- continue
- }
- } else if field.DataIndex == "title" && c.Ctitle == "" {
- _, err := l.svcCtx.DB.Contact.Update().
- Where(contact.WxWxidEQ(botID), contact.WxidEQ(receiverID)).
- SetCtitle(field.Value[0]).
- Save(l.ctx)
- if err != nil {
- continue
- }
- }
- } else {
- f, _ := l.svcCtx.DB.ContactField.Query().Where(contactfield.ContactID(c.ID), contactfield.FormID(field.DataIndex)).First(l.ctx)
- if f == nil {
- if field.Value != nil && len(field.Value) > 0 && field.Value[0] != "" {
- _, err := l.svcCtx.DB.ContactField.Create().
- SetContactID(c.ID).
- SetFormID(field.DataIndex).
- SetValue(field.Value).
- Save(l.ctx)
- if err != nil {
- continue
- }
- }
- } else if len(f.Value) == 0 || f.Value[0] == "" {
- if field.Value != nil && len(field.Value) > 0 && field.Value[0] != "" {
- _, err := l.svcCtx.DB.ContactField.UpdateOneID(f.ID).
- SetValue(field.Value).
- Save(l.ctx)
- if err != nil {
- continue
- }
- }
- }
- }
- }
- return nil
- }
- func ConvertFormData(input []custom_types.ContactFieldTemplate) []FormData {
- result := make([]FormData, len(input))
- for i, item := range input {
- options := make([]FieldPropsOptions, len(item.Options))
- for j, opt := range item.Options {
- options[j] = FieldPropsOptions{
- Label: *opt.Label,
- Value: *opt.Value,
- }
- }
- result[i] = FormData{
- Title: *item.Label,
- DataIndex: *item.Id,
- ValueType: *item.Type,
- FieldProps: FieldProps{
- Options: options,
- },
- }
- }
- return result
- }
- func contains(strs []string, target string) bool {
- for _, s := range strs {
- if s == target {
- return true
- }
- }
- return false
- }
- func parseContent(content string) ([]ResponseItem, error) {
- content = strings.TrimSpace(content)
- // ① 双引号包裹的再来一次:"{\"dataIndex\":...}"
- if unq, err := strconv.Unquote(content); err == nil {
- return parseContent(unq) // 尝试递归
- }
- // ② 直接数组形式: [...]
- if strings.HasPrefix(content, "[") {
- var list []ResponseItem
- if err := json.Unmarshal([]byte(content), &list); err == nil {
- return list, nil
- }
- }
- // ③ 对象形式
- if strings.HasPrefix(content, "{") {
- // 3‑1 尝试对象包裹数组: {"values":[...]}
- var wrapper struct {
- Values []ResponseItem `json:"values"`
- }
- if err := json.Unmarshal([]byte(content), &wrapper); err == nil && len(wrapper.Values) > 0 {
- return wrapper.Values, nil
- }
- // 3‑2 尝试单对象形式: {"dataIndex": ...}
- var item ResponseItem
- if err := json.Unmarshal([]byte(content), &item); err == nil {
- return []ResponseItem{item}, nil
- }
- }
- return nil, fmt.Errorf("unsupported content format: %q", content)
- }
|