diff --git a/docs/jim.sql b/docs/jim.sql index 8aad2c2..5c75152 100644 --- a/docs/jim.sql +++ b/docs/jim.sql @@ -848,4 +848,19 @@ CREATE TABLE `grpapplications` ( KEY `idx_recipient` (`app_key`,`apply_type`,`recipient_id`,`apply_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT '群申请表'; +DROP TABLE IF EXISTS `botconfs`; +CREATE TABLE `botconfs` ( + `id` int NOT NULL AUTO_INCREMENT, + `bot_id` varchar(32) NULL, + `nickname` varchar(50) DEFAULT NULL, + `bot_portrait` varchar(200) DEFAULT NULL, + `bot_type` tinyint DEFAULT '0', + `bot_conf` varchar(2000) NULL, + `updated_time` datetime(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + `created_time` datetime(3) DEFAULT CURRENT_TIMESTAMP(3), + `app_key` varchar(20) NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `uniq_botid` (`app_key`, `bot_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + INSERT IGNORE INTO `accounts`(`account`,`password`)VALUES('admin','7c4a8d09ca3762af61e59520943dc26494f8941b'); \ No newline at end of file diff --git a/services/appbusiness/apis/group.go b/services/appbusiness/apis/group.go index d413b33..398f4e7 100644 --- a/services/appbusiness/apis/group.go +++ b/services/appbusiness/apis/group.go @@ -15,10 +15,18 @@ func CreateGroup(ctx *httputils.HttpContext) { ctx.ResponseErr(errs.IMErrorCode_APP_REQ_BODY_ILLEGAL) return } + memberIds := req.MemberIds + if len(memberIds) <= 0 && len(req.GrpMembers) > 0 { + ids := []string{} + for _, member := range req.GrpMembers { + ids = append(ids, member.UserId) + } + memberIds = ids + } code, grpInfo := services.CreateGroup(ctx.ToRpcCtx(ctx.CurrentUserId), &pbobjs.GroupMembersReq{ GroupName: req.GroupName, GroupPortrait: req.GroupPortrait, - MemberIds: req.MemberIds, + MemberIds: memberIds, }) if code != errs.IMErrorCode_SUCCESS { ctx.ResponseErr(code) diff --git a/services/appbusiness/services/friendservice.go b/services/appbusiness/services/friendservice.go index 039ad07..6dd10e0 100644 --- a/services/appbusiness/services/friendservice.go +++ b/services/appbusiness/services/friendservice.go @@ -73,7 +73,10 @@ func ApplyFriend(ctx context.Context, req *pbobjs.ApplyFriend) errs.IMErrorCode userId := bases.GetRequesterIdFromCtx(ctx) //check friend relation if checkFriend(ctx, req.FriendId, userId) { - return errs.IMErrorCode_APP_FRIEND_APPLY_REPEATED + AppSyncRpcCall(ctx, "add_friends", userId, userId, &pbobjs.FriendIdsReq{ + FriendIds: []string{req.FriendId}, + }, nil) + return errs.IMErrorCode_SUCCESS } friendUserInfo := commonservices.GetTargetUserInfo(ctx, req.FriendId) friendSettings := GetUserSettings(friendUserInfo) diff --git a/services/botmsg/services/botengines/botengine.go b/services/botmsg/services/botengines/botengine.go new file mode 100644 index 0000000..31334f9 --- /dev/null +++ b/services/botmsg/services/botengines/botengine.go @@ -0,0 +1,14 @@ +package botengines + +import "context" + +var DefaultBotEngine IBotEngine = &NilBotEngine{} + +type IBotEngine interface { + StreamChat(ctx context.Context, senderId, converId string, question string, f func(answerPart string, isEnd bool)) +} + +type NilBotEngine struct{} + +func (engine *NilBotEngine) StreamChat(ctx context.Context, senderId, converId string, question string, f func(answerPart string, isEnd bool)) { +} diff --git a/services/botmsg/services/botengines/difyengine.go b/services/botmsg/services/botengines/difyengine.go new file mode 100644 index 0000000..a9e1305 --- /dev/null +++ b/services/botmsg/services/botengines/difyengine.go @@ -0,0 +1,90 @@ +package botengines + +import ( + "context" + "fmt" + "im-server/commons/tools" + "im-server/services/commonservices/logs" + "net/http" +) + +type DifyBotEngine struct { + ApiKey string `json:"api_key"` + Url string `json:"url"` +} + +func (engine *DifyBotEngine) StreamChat(ctx context.Context, senderId, converId string, question string, f func(answerPart string, isEnd bool)) { + req := &DifyChatMsgReq{ + Inputs: map[string]string{}, + Query: question, + ResponseMode: "streaming", + ConversationId: converId, + User: senderId, + } + body := tools.ToJson(req) + headers := map[string]string{} + headers["Authorization"] = fmt.Sprintf("Bearer %s", engine.ApiKey) + headers["Content-Type"] = "application/json" + stream, code, err := tools.CreateStream(http.MethodPost, engine.Url, headers, body) + if err != nil || code != http.StatusOK { + logs.WithContext(ctx).Errorf("call dify api failed. http_code:%d,err:%v", code, err) + return + } + for { + line, err := stream.Receive() + if err != nil { + f("", true) + return + } + item := DifyStreamRespItem{} + err = tools.JsonUnMarshal([]byte(line), &item) + if err != nil { + f("", true) + return + } + if item.Event == "message" { + f(item.Answer, false) + } else if item.Event == "message_end" { + f(item.Answer, true) + return + } + } +} + +type DifyChatMsgReq struct { + Inputs map[string]string `json:"inputs"` + Query string `json:"query"` + ResponseMode string `json:"response_mode"` + ConversationId string `json:"conversation_id"` + User string `json:"user"` +} + +type DifyStreamRespItem struct { + Event string `json:"event"` + ConversationId string `json:"conversation_id"` + MessageId string `json:"message_id"` + CreatedAt int64 `json:"created_at"` + TaskId string `json:"task_id"` + Id string `json:"id"` + Answer string `json:"answer"` + + Audio string `json:"audio"` +} + +type DifyMetaData struct { + Usage *DifyUsage `json:"usage"` +} + +type DifyUsage struct { + PromptTokens int32 `json:"prompt_tokens"` + PromptUnitPrice string `json:"prompt_price_unit"` + PromptPrice string `json:"prompt_price"` + CompletionTokens int32 `json:"completion_tokens"` + CompletionUnitPrice string `json:"completion_unit_price"` + CompletionPriceUnit string `json:"completion_price_unit"` + CompletionPrice string `json:"completion_price"` + TotalTokens int32 `json:"total_tokens"` + TotalPrice string `json:"total_price"` + Currency string `json:"currency"` + Latency float64 `json:"latency"` +} diff --git a/services/botmsg/services/botservice.go b/services/botmsg/services/botservice.go index d2ab82f..e644cc7 100644 --- a/services/botmsg/services/botservice.go +++ b/services/botmsg/services/botservice.go @@ -1,11 +1,15 @@ package services import ( + "bytes" "context" "im-server/commons/bases" "im-server/commons/caches" "im-server/commons/pbdefines/pbobjs" "im-server/commons/tools" + "im-server/services/botmsg/services/botengines" + "im-server/services/botmsg/storages" + "im-server/services/botmsg/storages/models" "im-server/services/commonservices" "im-server/services/commonservices/logs" "strings" @@ -21,13 +25,12 @@ func init() { } type BotInfo struct { + AppKey string BotId string Nickname string Portrait string - ExtFields []*pbobjs.KvItem - Webhook string - BotType string - APIKey string + BotType models.BotType + BotEngine botengines.IBotEngine } func GetBotInfo(ctx context.Context, botId string) *BotInfo { @@ -42,24 +45,27 @@ func GetBotInfo(ctx context.Context, botId string) *BotInfo { if val, exist := botCache.Get(key); exist { return val.(*BotInfo) } else { - bInfo := commonservices.GetUserInfoFromRpcWithAttTypes(ctx, botId, []int32{int32(commonservices.AttItemType_Setting)}) botInfo := &BotInfo{ - BotId: bInfo.UserId, - Nickname: bInfo.Nickname, - Portrait: bInfo.UserPortrait, - ExtFields: bInfo.ExtFields, + AppKey: appkey, + BotId: botId, + BotEngine: &botengines.NilBotEngine{}, } - if len(bInfo.Settings) > 0 { - settingMap := commonservices.Kvitems2Map(bInfo.Settings) - if webhook, exist := settingMap[string(commonservices.AttItemKey_Bot_WebHook)]; exist && webhook != "" { - botInfo.Webhook = webhook - } - if apiKey, exist := settingMap[string(commonservices.AttItemKey_Bot_ApiKey)]; exist && apiKey != "" { - botInfo.APIKey = apiKey - } - if botType, exist := settingMap[string(commonservices.AttItemKey_Bot_Type)]; exist && botType != "" { - botInfo.BotType = botType + storage := storages.NewBotConfStorage() + bot, err := storage.FindById(appkey, botId) + if err == nil { + botInfo.Nickname = bot.Nickname + botInfo.Portrait = bot.BotPortrait + botInfo.BotType = bot.BotType + switch botInfo.BotType { + case models.BotType_Dify: + difyBot := &botengines.DifyBotEngine{} + err = tools.JsonUnMarshal([]byte(bot.BotConf), difyBot) + if err == nil && difyBot.ApiKey != "" && difyBot.Url != "" { + botInfo.BotEngine = difyBot + } } + } else { + botInfo.BotEngine = &botengines.NilBotEngine{} } botCache.Add(key, botInfo) return botInfo @@ -72,17 +78,37 @@ func getKey(appkey, botId string) string { } func HandleBotMsg(ctx context.Context, msg *pbobjs.DownMsg) { + if msg.MsgType != "jg:text" { + return + } + txtMsg := &commonservices.TextMsg{} + err := tools.JsonUnMarshal(msg.MsgContent, txtMsg) + if err != nil { + logs.WithContext(ctx).Errorf("text msg illigal. content:%s", string(msg.MsgContent)) + return + } botId := bases.GetTargetIdFromCtx(ctx) botInfo := GetBotInfo(ctx, botId) - if botInfo.BotType == "dify" { - if botInfo.Webhook == "" || botInfo.APIKey == "" { - logs.WithContext(ctx).Infof("no webhook/apikey") - return + if botInfo.BotEngine != nil { + converId := "" + buf := bytes.NewBuffer([]byte{}) + botInfo.BotEngine.StreamChat(ctx, msg.SenderId, converId, txtMsg.Content, func(answerPart string, isEnd bool) { + if !isEnd { + buf.WriteString(answerPart) + } + }) + answer := buf.String() + if answer != "" { + answerMsg := &commonservices.TextMsg{ + Content: answer, + } + flag := commonservices.SetStoreMsg(0) + flag = commonservices.SetCountMsg(flag) + commonservices.AsyncPrivateMsgOverUpstream(ctx, botId, msg.SenderId, &pbobjs.UpMsg{ + MsgType: "jg:text", + MsgContent: []byte(tools.ToJson(answerMsg)), + Flags: flag, + }) } - //https://api.dify.ai/v1/chat-messages - //app-UD0yqEwQykpxA8hMbtzP0ktz - Chat2Dify(ctx, botId, msg, botInfo.Webhook, botInfo.APIKey) - } else { - SyncMsg2Bot(ctx, botId, msg) } } diff --git a/services/botmsg/services/difybotservice.go b/services/botmsg/services/difybotservice.go deleted file mode 100644 index cad9291..0000000 --- a/services/botmsg/services/difybotservice.go +++ /dev/null @@ -1,116 +0,0 @@ -package services - -import ( - "context" - "encoding/json" - "fmt" - "im-server/commons/pbdefines/pbobjs" - "im-server/commons/tools" - "im-server/services/commonservices" - "im-server/services/commonservices/logs" - "net/http" -) - -func Chat2Dify(ctx context.Context, botId string, msg *pbobjs.DownMsg, webhook, apiKey string) { - if msg.MsgType == "jg:text" { - var txtMsg commonservices.TextMsg - err := tools.JsonUnMarshal(msg.MsgContent, txtMsg) - if err != nil { - logs.WithContext(ctx).Errorf("text msg illigal. content:%s", string(msg.MsgContent)) - return - } - req := &ChatMsgReq{ - Inputs: map[string]string{}, - Query: txtMsg.Content, - ResponseMode: "streaming", - ConversationId: "", - User: "", - } - bs, _ := json.Marshal(req) - body := string(bs) - headers := map[string]string{} - headers["Authorization"] = fmt.Sprintf("Bearer %s", apiKey) - headers["Content-Type"] = "application/json" - stream, code, err := tools.CreateStream(http.MethodPost, webhook, headers, body) - if err != nil || code != http.StatusOK { - logs.WithContext(ctx).Errorf("call dify api failed. http_code:%d,err:%v", code, err) - return - } - for { - line, err := stream.Receive() - if err != nil { - fmt.Println("xxxx:", err) - return - } - fmt.Println(line) - } - } -} - -func TestDify() { - url := "https://api.dify.ai/v1/chat-messages" - req := &ChatMsgReq{ - Inputs: map[string]string{}, - Query: "What are the specs of the iPhone 13 Pro Max?", - ResponseMode: "streaming", - ConversationId: "", - User: "userid1", - } - bs, _ := json.Marshal(req) - body := string(bs) - headers := map[string]string{} - headers["Authorization"] = "Bearer app-UD0yqEwQykpxA8hMbtzP0ktz" - headers["Content-Type"] = "application/json" - - stream, code, err := tools.CreateStream("POST", url, headers, body) - fmt.Println("code:", code) - if err != nil { - fmt.Println(err) - return - } - - for { - line, err := stream.Receive() - if err != nil { - fmt.Println("xxxx:", err) - return - } - fmt.Println(line) - } -} - -type ChatMsgReq struct { - Inputs map[string]string `json:"inputs"` - Query string `json:"query"` - ResponseMode string `json:"response_mode"` - ConversationId string `json:"conversation_id"` - User string `json:"user"` -} - -type StreamRespItem struct { - Event string `json:"event"` - ConversationId string `json:"conversation_id"` - MessageId string `json:"message_id"` - CreatedAt int64 `json:"created_at"` - TaskId string `json:"task_id"` - Id string `json:"id"` - Answer string `json:"answer"` - - Audio string `json:"audio"` -} -type MetaData struct { - Usage *Usage `json:"usage"` -} -type Usage struct { - PromptTokens int32 `json:"prompt_tokens"` - PromptUnitPrice string `json:"prompt_price_unit"` - PromptPrice string `json:"prompt_price"` - CompletionTokens int32 `json:"completion_tokens"` - CompletionUnitPrice string `json:"completion_unit_price"` - CompletionPriceUnit string `json:"completion_price_unit"` - CompletionPrice string `json:"completion_price"` - TotalTokens int32 `json:"total_tokens"` - TotalPrice string `json:"total_price"` - Currency string `json:"currency"` - Latency float64 `json:"latency"` -} diff --git a/services/botmsg/services/syncmsgbotservice.go b/services/botmsg/services/syncmsgbotservice.go index d11e4e2..236dccd 100644 --- a/services/botmsg/services/syncmsgbotservice.go +++ b/services/botmsg/services/syncmsgbotservice.go @@ -1,17 +1,9 @@ package services import ( - "context" - "fmt" - "im-server/commons/bases" - "im-server/commons/pbdefines/pbobjs" - "im-server/commons/tools" - "im-server/services/commonservices/logs" - "net/http" "time" "github.com/avast/retry-go/v4" - "github.com/zeromicro/go-zero/core/breaker" ) var retryStrategy = []retry.Option{ @@ -48,6 +40,7 @@ type MentionInfo struct { TargetUserIds []string `json:"target_user_ids"` } +/* func SyncMsg2Bot(ctx context.Context, botId string, msg *pbobjs.DownMsg) { appkey := bases.GetAppKeyFromCtx(ctx) botInfo := GetBotInfo(ctx, botId) @@ -98,3 +91,4 @@ func notify(url string, headers map[string]string, body string) error { } return nil } +*/ diff --git a/services/botmsg/storages/dbs/botconfdao.go b/services/botmsg/storages/dbs/botconfdao.go new file mode 100644 index 0000000..48ac482 --- /dev/null +++ b/services/botmsg/storages/dbs/botconfdao.go @@ -0,0 +1,42 @@ +package dbs + +import ( + "fmt" + "im-server/commons/dbcommons" + "im-server/services/botmsg/storages/models" +) + +type BotConfDao struct { + ID int64 `gorm:"primary_key"` + BotId string `gorm:"bot_id"` + Nickname string `gorm:"nickname"` + BotPortrait string `gorm:"bot_portrait"` + BotType int `gorm:"bot_type"` + BotConf string `gorm:"bot_conf"` + AppKey string `gorm:"app_key"` +} + +func (conf BotConfDao) TableName() string { + return "botconfs" +} + +func (conf BotConfDao) Upsert(item models.BotConf) error { + sql := fmt.Sprintf("INSERT INTO %s (app_key,bot_id,nickname,bot_portrait,bot_type,bot_conf)VALUES(?,?,?,?,?,?) ON DUPLICATE KEY UPDATE bot_type=VALUES(bot_type), bot_conf=VALUES(bot_conf)", conf.TableName()) + return dbcommons.GetDb().Exec(sql, item.AppKey, item.BotId, item.Nickname, item.BotPortrait, item.BotType, item.BotConf).Error +} + +func (conf BotConfDao) FindById(appkey, botId string) (*models.BotConf, error) { + var item BotConfDao + err := dbcommons.GetDb().Where("app_key=? and bot_id=?", appkey, botId).Take(&item).Error + if err != nil { + return nil, err + } + return &models.BotConf{ + AppKey: item.AppKey, + BotId: item.BotId, + Nickname: item.Nickname, + BotPortrait: item.BotPortrait, + BotType: models.BotType(item.BotType), + BotConf: item.BotConf, + }, err +} diff --git a/services/botmsg/storages/models/botconf.go b/services/botmsg/storages/models/botconf.go new file mode 100644 index 0000000..a2ec672 --- /dev/null +++ b/services/botmsg/storages/models/botconf.go @@ -0,0 +1,25 @@ +package models + +type BotType int + +var ( + BotType_Default BotType = 0 + BotType_Custom BotType = 1 + BotType_Dify BotType = 2 + BotType_Minmax BotType = 3 +) + +type BotConf struct { + ID int64 + AppKey string + BotId string + Nickname string + BotPortrait string + BotType BotType + BotConf string +} + +type IBotConfStorage interface { + Upsert(item BotConf) error + FindById(appkey, botId string) (*BotConf, error) +} diff --git a/services/botmsg/storages/storage.go b/services/botmsg/storages/storage.go index de9c0f1..a650d85 100644 --- a/services/botmsg/storages/storage.go +++ b/services/botmsg/storages/storage.go @@ -1 +1,10 @@ package storages + +import ( + "im-server/services/botmsg/storages/dbs" + "im-server/services/botmsg/storages/models" +) + +func NewBotConfStorage() models.IBotConfStorage { + return &dbs.BotConfDao{} +} diff --git a/services/group/services/groupmemberservice.go b/services/group/services/groupmemberservice.go index b766d0b..38920ea 100644 --- a/services/group/services/groupmemberservice.go +++ b/services/group/services/groupmemberservice.go @@ -300,8 +300,8 @@ func SetGroupMemberAllow(ctx context.Context, req *pbobjs.GroupMemberAllowReq) e func SetGroupMemberSettings(ctx context.Context, groupId string, req *pbobjs.GroupMember) errs.IMErrorCode { appkey := bases.GetAppKeyFromCtx(ctx) dao := dbs.GroupMemberExtDao{} - memberAtts, exist := GetGrpMemberAttsFromCache(ctx, appkey, groupId, req.MemberId) - if exist { + memberAtts := GetGrpMemberAttsFromCache(ctx, appkey, groupId, req.MemberId) + if memberAtts != nil { for _, setting := range req.Settings { memberAtts.SetMemberSetting(setting.Key, setting.Value) dao.Upsert(appkey, groupId, req.MemberId, setting.Key, setting.Value, int(commonservices.AttItemType_Setting)) @@ -401,8 +401,8 @@ func QryMemberSettings(ctx context.Context, groupId string, memberId string) (er if member != nil { resp.IsMember = true resp.JoinTime = member.CreatedTime - memberAtts, exist := GetGrpMemberAttsFromCache(ctx, appkey, groupId, memberId) - if exist { + memberAtts := GetGrpMemberAttsFromCache(ctx, appkey, groupId, memberId) + if memberAtts != nil { resp.MemberSettings = memberAtts.GetMemberSettings() resp.MemberExts = memberAtts.GetMemberExts() } diff --git a/services/group/services/memberattservice.go b/services/group/services/memberattservice.go index d6e7013..54b7efb 100644 --- a/services/group/services/memberattservice.go +++ b/services/group/services/memberattservice.go @@ -18,11 +18,6 @@ func init() { memberLocks = tools.NewSegmentatedLocks(512) } -var notExistGrpMemberAtts MemberAtts = MemberAtts{ - ExtFields: make(map[string]string), - Settings: &commonservices.GrpMemberSettings{}, -} - type MemberAtts struct { AppKey string GroupId string @@ -78,15 +73,11 @@ func AddGrpMemberAtts2Cache(ctx context.Context, appkey, groupId, memberId strin memberAttCache.Add(key, &atts) } -func GetGrpMemberAttsFromCache(ctx context.Context, appkey, groupId, memberId string) (*MemberAtts, bool) { +func GetGrpMemberAttsFromCache(ctx context.Context, appkey, groupId, memberId string) *MemberAtts { key := getGrpMemberKey(appkey, groupId, memberId) if val, exist := memberAttCache.Get(key); exist { memberAtts := val.(*MemberAtts) - if memberAtts == ¬ExistGrpMemberAtts { - return nil, false - } else { - return memberAtts, true - } + return memberAtts } else { l := memberLocks.GetLocks(key) l.Lock() @@ -94,33 +85,27 @@ func GetGrpMemberAttsFromCache(ctx context.Context, appkey, groupId, memberId st if val, exist := memberAttCache.Get(key); exist { memberAtts := val.(*MemberAtts) - if memberAtts == ¬ExistGrpMemberAtts { - return nil, false - } else { - return memberAtts, true - } + return memberAtts } else { memberAtts := getGrpMemberAttsFromDb(ctx, appkey, groupId, memberId) memberAttCache.Add(key, memberAtts) - return memberAtts, memberAtts != ¬ExistGrpMemberAtts + return memberAtts } } } func getGrpMemberAttsFromDb(ctx context.Context, appkey, groupId, memberId string) *MemberAtts { + ret := &MemberAtts{ + AppKey: appkey, + GroupId: groupId, + MemberId: memberId, + ExtFields: make(map[string]string), + Settings: &commonservices.GrpMemberSettings{}, + SettingFields: make(map[string]string), + } dao := dbs.GroupMemberExtDao{} exts, err := dao.QryExtFields(appkey, groupId, memberId) - if err != nil || len(exts) <= 0 { - return ¬ExistGrpMemberAtts - } else { - ret := &MemberAtts{ - AppKey: appkey, - GroupId: groupId, - MemberId: memberId, - ExtFields: make(map[string]string), - Settings: &commonservices.GrpMemberSettings{}, - SettingFields: make(map[string]string), - } + if err == nil && len(exts) > 0 { grpInfo, exist := GetGroupInfoFromCache(ctx, appkey, groupId) hideGrpMsg := "0" if exist && grpInfo != nil && grpInfo.Settings != nil { @@ -139,8 +124,8 @@ func getGrpMemberAttsFromDb(ctx context.Context, appkey, groupId, memberId strin } } commonservices.FillObjField(ret.Settings, valMap) - return ret } + return ret } func getGrpMemberKey(appkey, groupId, memberId string) string { diff --git a/services/usermanager/actors/upstreamactor.go b/services/usermanager/actors/upstreamactor.go index 2118f63..85ff57c 100644 --- a/services/usermanager/actors/upstreamactor.go +++ b/services/usermanager/actors/upstreamactor.go @@ -32,6 +32,7 @@ func (actor *UpstreamActor) OnReceive(ctx context.Context, input proto.Message) if exist && user != nil { userInfo.Nickname = user.Nickname userInfo.UserPortrait = user.UserPortrait + userInfo.UserType = pbobjs.UserType(user.UserType) userInfo.UpdatedTime = user.UpdatedTime userInfo.ExtFields = commonservices.Map2KvItems(user.ExtFields) //check private global mute