package service import ( "context" "encoding/json" "errors" "fmt" "github.com/gorilla/websocket" "github.com/tidwall/gjson" "google.golang.org/grpc/metadata" "io" "net" "speech-nlu-parse/global" "speech-nlu-parse/model" "speech-nlu-parse/pkg/errCode" "speech-nlu-parse/pkg/logger" "speech-nlu-parse/pkg/proto" "speech-nlu-parse/service/connect" "speech-nlu-parse/service/speechNlu" "speech-nlu-parse/service/tencentNlu" ) type TencentNlu struct { proto.UnimplementedTencentNluServer } func TencentNluParseSemanticRequest2ModelSemanticReq(tencentNluParseSemanticRequest *proto.SemanticRequest) *model.SemanticReq { if tencentNluParseSemanticRequest == nil { return nil } var lbs *model.Lbs if tencentNluParseSemanticRequest.GetLbs() == nil { lbs = nil } else { lbs = &model.Lbs{ Longitude: tencentNluParseSemanticRequest.GetLbs().GetLongitude(), Latitude: tencentNluParseSemanticRequest.GetLbs().GetLatitude(), } } var addressInfo *model.AddressInfo if tencentNluParseSemanticRequest.GetAddressInfo() == nil { addressInfo = &model.AddressInfo{} } else { addressInfo = &model.AddressInfo{ Province: tencentNluParseSemanticRequest.GetAddressInfo().GetProvince(), City: tencentNluParseSemanticRequest.GetAddressInfo().GetCity(), County: tencentNluParseSemanticRequest.GetAddressInfo().GetCounty(), } } var semanticReqNativateData *model.SemanticReqNativeData if tencentNluParseSemanticRequest.GetNative().GetData() == nil { semanticReqNativateData = nil } else { semanticReqNativateData = &model.SemanticReqNativeData{ // TODO: Native API协议数据, 由云端和客户端一起定义 } } var native *model.SemanticReqNative if tencentNluParseSemanticRequest.GetNative() == nil { native = nil } else { native = &model.SemanticReqNative{ Name: tencentNluParseSemanticRequest.GetNative().GetName(), SeqID: tencentNluParseSemanticRequest.GetNative().GetSeqID(), Code: int(tencentNluParseSemanticRequest.GetNative().GetCode()), Message: tencentNluParseSemanticRequest.GetNative().GetMessage(), DataVersion: tencentNluParseSemanticRequest.GetNative().GetDataVersion(), Data: semanticReqNativateData, } } var sdkExtend *model.SemanticReqSDKExtend if tencentNluParseSemanticRequest.GetSdkExtend() == nil { sdkExtend = nil } else { sdkExtend = &model.SemanticReqSDKExtend{ CarDOA: int(tencentNluParseSemanticRequest.GetSdkExtend().GetCarDOA()), LastRspType: tencentNluParseSemanticRequest.GetSdkExtend().GetLastRspType(), LastRspResult: tencentNluParseSemanticRequest.GetSdkExtend().GetLastRspResult(), LastSessionStatus: int(tencentNluParseSemanticRequest.GetSdkExtend().GetLastSessionStatus()), LastCompleteCmdResult: tencentNluParseSemanticRequest.GetSdkExtend().GetLastCompleteCmdResult(), } } semanticReq := &model.SemanticReq{ MacWifi: tencentNluParseSemanticRequest.MacWifi, MacVoice: tencentNluParseSemanticRequest.MacVoice, Query: tencentNluParseSemanticRequest.Query, Ip: tencentNluParseSemanticRequest.Ip, TestID: tencentNluParseSemanticRequest.TestID, OriginQuery: tencentNluParseSemanticRequest.OriginQuery, Mid: tencentNluParseSemanticRequest.Mid, RequestId: tencentNluParseSemanticRequest.RequestId, Lbs: lbs, Vender: tencentNluParseSemanticRequest.GetVender(), Appkey: tencentNluParseSemanticRequest.GetAppKey(), AccessToken: tencentNluParseSemanticRequest.GetAccessToken(), Qua: tencentNluParseSemanticRequest.GetQua(), Auth: tencentNluParseSemanticRequest.GetAuth(), Dsn: tencentNluParseSemanticRequest.GetDsn(), Guid: tencentNluParseSemanticRequest.GetGuid(), Exist: tencentNluParseSemanticRequest.GetExist(), TRequestId: tencentNluParseSemanticRequest.GetTRequestId(), RequestType: tencentNluParseSemanticRequest.GetRequestType(), CommType: tencentNluParseSemanticRequest.GetCommType(), CharacterID: tencentNluParseSemanticRequest.GetCharacterID(), Event: tencentNluParseSemanticRequest.GetEvent(), Nativate: native, SDKExtend: sdkExtend, AddressInfo: addressInfo, Language: tencentNluParseSemanticRequest.GetLanguage(), } return semanticReq } /* { "macwifi":"8812ac3333f0", "ip":"120.198.22.24", "mid":"70601", "requestid":"81e61c5f-d909-11ed-a4b5-02420a0a7d8a", "vender":"01", "appkey":"9756a52091cb11ed8ac31111cf5d8985", "accesstoken":"853c1d62325346f18c0dac6f40e1128f", "qua":"QV=3\u0026VN=MC-VTSBH02V1.0\u0026DE=CENTRALCONTROL\u0026BD=70601_01\u0026VC=GREE\u0026PL=LINUX", "auth":"BACKEND-ENCRYPT:1000,MTAsMTAxNjk4MjcxNTIwNTAyOTg4OCxBNTJEMTVBREE3RUIxRDhBOEFGOTA0QUQ2NDU0REM1MllYV1YwLGFfOGFiY2Q5OWNiMzk4MGVhMDg3MzkxMDc5NWFkMzdlOWQ2NTQ0ZWYwZSw5NzU2YTUyMDkxY2IxMWVkOGFjMzExMTFjZjVkODk4NTo4NTNjMWQ2MjMyNTM0NmYxOGMwZGFjNmY0MGUxMTI4ZixHUkVFX1NtYXJ0X1NjcmVlbl8wMDYsQTUyRDE1QURBN0VCMUQ4QThBRjkwNEFENjQ1NERDNTJZWFdWMA==", "dsn":"GREE_Smart_Screen_006", "exist":"1", "trequestid":"gzde4c62b816812695777577573" } */ func GetSemanticReq(md map[string][]string) (*model.TencentNluParseStreamMetaData, error) { var metaData model.TencentNluParseStreamMetaData if macWifi, ok := md["macwifi"]; ok { metaData.MacWifi = macWifi[0] } else { global.Logger.Error("metadata macwifi not found.") return nil, errors.New("metadata macwifi not found.") } if ip, ok := md["ip"]; ok { metaData.Ip = ip[0] } else { global.Logger.Error("metadata ip not found.") return nil, errors.New("metadata ip not found.") } if mid, ok := md["mid"]; ok { metaData.Mid = mid[0] } else { global.Logger.Error("metadata mid not found.") return nil, errors.New("metadata mid not found.") } if requestId, ok := md["requestid"]; ok { metaData.RequestId = requestId[0] } else { global.Logger.Error("metadata requestid not found.") return nil, errors.New("metadata requestid not found.") } if vender, ok := md["vender"]; ok { metaData.Vender = vender[0] } else { global.Logger.Error("metadata vender not found.") return nil, errors.New("metadata vender not found.") } if appkey, ok := md["appkey"]; ok { metaData.Appkey = appkey[0] } else { global.Logger.Error("metadata appkey not found.") return nil, errors.New("metadata appkey not found.") } if accessToken, ok := md["accesstoken"]; ok { metaData.AccessToken = accessToken[0] } else { global.Logger.Error("metadata accesstoken not found.") return nil, errors.New("metadata accesstoken not found.") } if qua, ok := md["qua"]; ok { metaData.Qua = qua[0] } else { global.Logger.Error("metadata qua not found.") return nil, errors.New("metadata qua not found.") } if auth, ok := md["auth"]; ok { metaData.Auth = auth[0] } else { global.Logger.Error("metadata qua not found.") return nil, errors.New("metadata qua not found.") } if dsn, ok := md["dsn"]; ok { metaData.Dsn = dsn[0] } else { global.Logger.Error("metadata qua not found.") return nil, errors.New("metadata qua not found.") } if exist, ok := md["exist"]; ok { metaData.Exist = exist[0] == "1" } else { global.Logger.Error("metadata exist not found.") return nil, errors.New("metadata exist not found.") } if tRequestId, ok := md["trequestid"]; ok { metaData.TRequestId = tRequestId[0] } else { global.Logger.Error("metadata trequestid not found.") return nil, errors.New("metadata trequestid not found.") } if sessionId, ok := md["sessionid"]; ok { metaData.SessionId = sessionId[0] } else { global.Logger.Error("metadata trequestid not found.") return nil, errors.New("metadata trequestid not found.") } if homeId, ok := md["home_id"]; ok { metaData.HomeId = homeId[0] } else { global.Logger.Error("metadata homeId not found.") // return nil, errors.New("metadata homeId not found.") } return &metaData, nil } func (this TencentNlu) TencentNluParse(ctx context.Context, r *proto.SemanticRequest) (*proto.SemanticResponse, error) { requestBody, _ := json.Marshal(r) global.Logger.WithFields(logger.Fields{"data": map[string]interface{}{"requestBody": string(requestBody), "query": r.GetQuery()}, "mac": r.GetMacWifi(), "mid": r.GetMid(), "vender": r.GetVender(), "requestId": r.RequestId, "ip": r.Ip}).Info("speech-nlu-parse-grpc request") semanticReq := TencentNluParseSemanticRequest2ModelSemanticReq(r) fmt.Println(semanticReq) jsonStr, code := speechNlu.SpeechNlu(semanticReq) responseText := gjson.Get(jsonStr, "response_text").String() response := &proto.SemanticResponse{Status: &proto.Status{Code: code.Code(), Msg: code.Msg()}, Data: &proto.SemanticData{SemanticRespJsonData: jsonStr}} responseBody, _ := json.Marshal(response) defer global.Logger.WithFields(logger.Fields{"data": map[string]interface{}{"responseBody": string(responseBody), "query": r.GetQuery(), "responseText": responseText}, "mac": r.GetMacWifi(), "mid": r.GetMid(), "vender": r.GetVender(), "requestId": r.RequestId, "ip": r.Ip}).Info("speech-nlu-parse-grpc response") return response, nil } func (TencentNlu) TencentNluParseStream(stream proto.TencentNlu_TencentNluParseStreamServer) error { ctx := stream.Context() md, ok := metadata.FromIncomingContext(stream.Context()) if !ok { global.Logger.Errorf("获取metadata失败:%v", md) return nil } tMetaData, err := GetSemanticReq(md) if err != nil { global.Logger.Errorf("获取metadata失败:%v", md) return err } if tMetaData == nil { global.Logger.Errorf("获取metadata失败:%v", md) return nil } sessionId := tMetaData.SessionId vender := tMetaData.Vender var appKey, auth, dsn, qua, requestId, mid, mac, ip string qua = "QV=3&PL=ADR&PR=chvoice&VE=7.6&VN=3350&PP=com.geli.mtt&DE=SPEAKER&SP=3" requestId = tMetaData.RequestId mid = tMetaData.Mid mac = tMetaData.MacWifi ip = tMetaData.Ip // 查询key和secret //dingDangBot, ok := global.DingDangBot.Get(tMetaData.Mid, tMetaData.Vender) //if ok { // appKey = dingDangBot.Key // accessToken = dingDangBot.Secret //} //if tMetaData.Exist { // appKey = tMetaData.Appkey // accessToken = tMetaData.AccessToken // auth = tMetaData.Auth // dsn = tMetaData.Dsn // qua = tMetaData.Qua //} else { // // 没有携带鉴权信息, 查dmsdk // var tokenSearchResponse *model.TokenSearchResponse // tokenSearchResponse, err = tencentNlu.GetAuthorizationByGRPC(tMetaData.MacWifi, tMetaData.RequestId, mid, tMetaData.Vender) // if err != nil { // global.Logger.WithFields(logger.Fields{ // "data": map[string]interface{}{"data.MacWifi": tMetaData.MacWifi}, // "requestId": tMetaData.RequestId, // "mac": mac, // "mid": mid, // "vender": vender, // "sessionId": sessionId, // }).Error("GetTencentNLUData: GetAuthorizationByGRPC error." + err.Error()) // } else { // if tokenSearchResponse.Status.Code == 200 { // // 200: 成功; 405: 设备未激活 // if tokenSearchResponse.Data.Status != 0 { // 未分配 的情况下无AppKey AccessToken // if tokenSearchResponse.Data.AppKey != "" && tokenSearchResponse.Data.AccessToken != "" { // appKey = tokenSearchResponse.Data.AppKey // accessToken = tokenSearchResponse.Data.AccessToken // } // } // if tokenSearchResponse.Data.Status == 2 { // 已授权,使用中 // auth = tokenSearchResponse.Data.Authorization // dsn = tokenSearchResponse.Data.Dsn // } // if tokenSearchResponse.Data.HomeId != "" { // homeId = tokenSearchResponse.Data.HomeId // } // } else if tokenSearchResponse.Status.Code == 405 { // 未分配 // // // } else { // 错误码 // global.Logger.WithFields(logger.Fields{ // "data": map[string]interface{}{"tokenSearchResponse": tokenSearchResponse}, // "requestId": tMetaData.RequestId, // "mac": mac, // "mid": mid, // "vender": vender, // "sessionId": sessionId, // }).Error("GetTencentNLUData: GetAuthorizationByGRPC error." + tokenSearchResponse.Status.Msg) // } // } //} // 特殊处理, tencentllmtest001 将使用特殊的bot, 重新配网后会失效 // if mac == "tencentllmtest001" { // auth = "BACKEND-ENCRYPT:1000,MTAsMTAxNjk4MjcxNTIwNTAyOTg4OCw0MUNFM0QyMjRGNTcyMjg3NTA0NjcxRkEyMEI3ODc5NFlYV1YwLGFfYzg2ODI3M2ZlNjgwMGJhNTcwMzFlMGZjZDE4MjEzZjA4Mjg0ZTM0MixhNTllOTRiMDUyYWMxMWVlYWZmYWUzMTUwYzg5NDViMjphNTQ0ZDliOTY1OGE0NTkxODM0Y2Y5YzExMmRkYWY2MSx0ZXN0N2QzNTMyNmY4N2JjNDE2MTg1MmQ2Mzk2ZjFhMGVhMDQsNDFDRTNEMjI0RjU3MjI4NzUwNDY3MUZBMjBCNzg3OTRZWFdWMA==" // dsn = "test7d35326f87bc4161852d6396f1a0ea04" // appKey = "a544d9b9658a4591834cf9c112ddaf61" // accessToken = "a59e94b052ac11eeaffae3150c8945b2" // } var productId, deviceId string token, err := connect.TokenGrpc(requestId, mac, mid, vender) if err != nil || token.GetData().GetDeviceId() == "" { global.Logger.WithFields(logger.Fields{ "deviceId": token.GetData().GetProductId(), "productId": token.GetData().GetProductId(), }).Errorf("connect.TokenGrpc err: %v", err) return err //productId = global.SpeechSetting.ProductId //deviceId = util.EncodeMD5(mac) } else { productId = token.GetData().ProductId deviceId = token.GetData().DeviceId } speechNluWs := speechNlu.SpeechNlpWs{} var nlpWsConn *websocket.Conn //deviceId := util.EncodeMD5(mac) nlpWsConn, err = speechNluWs.SpeechWs(ip, productId, deviceId, mid) if err != nil { global.Logger.Errorf("speechWs.SpeechWs error. %v", err) return err } speechNluWs.NlpWsConn = nlpWsConn defer nlpWsConn.Close() cancelCtx, cancel := context.WithCancel(context.Background()) // 监听腾讯 go func() { defer func() { if err := recover(); err != nil { global.Logger.WithFields(logger.Fields{ "requestId": requestId, "mac": mac, "mid": mid, "vender": vender, "sessionId": sessionId, }).Errorf("err:%v", err) nlpWsConn.Close() cancel() return } }() for { select { case <-cancelCtx.Done(): nlpWsConn.Close() return default: data, err := speechNluWs.Recv() if err != nil { if websocket.IsCloseError(err, websocket.CloseAbnormalClosure) || errors.Is(err, net.ErrClosed) { // 服务端关闭及客户端关闭的错误捕获 global.Logger.WithFields(logger.Fields{ "requestId": requestId, "mac": mac, "mid": mid, "vender": vender, "sessionId": sessionId, }).Info("SpeechNluParseStream websocket closed.") } else { global.Logger.WithFields(logger.Fields{ "requestId": requestId, "mac": mac, "mid": mid, "vender": vender, "sessionId": sessionId, }).Errorf("SpeechNluParseStream speechNluWs.Recv error. %v", err) } nlpWsConn.Close() cancel() return } global.Logger.WithFields(logger.Fields{ "data": map[string]interface{}{"tencentNluParseStreamBody": string(data)}, "requestId": requestId, "mac": mac, "mid": mid, "vender": vender, "sessionId": sessionId, }).Info("SpeechNluParseStream speechNluWs.Recv.") // 解析 // tencentNluWs := tencentNlu.TencentNlpWs{} res := speechNluWs.ParseSpeechNluData(data, requestId, sessionId) if len(res) == 0 { // res 为空, 表示不需要返回 continue } code := errCode.Success resp := &proto.SemanticResponse{Status: &proto.Status{Code: code.Code(), Msg: code.Msg()}, Data: &proto.SemanticData{SemanticRespJsonData: string(res)}} stream.Send(resp) responseText := gjson.GetBytes(res, "response_text").String() responseBody, _ := json.Marshal(resp) global.Logger.WithFields(logger.Fields{ "data": map[string]interface{}{ "speechNluParseStreamBody": string(responseBody), "responseText": responseText, }, "requestId": requestId, "mac": mac, "mid": mid, "vender": vender, "sessionId": sessionId, }).Info("SpeechNluParseStream stream.Send.") responseType := gjson.GetBytes(res, "header.semantic.ResponseType").String() if responseType == "semantic.close" { nlpWsConn.Close() cancel() return } } } }() // 不主动关闭连接 for { data, err := stream.Recv() if err != nil { if errors.Is(ctx.Err(), context.Canceled) { // 客户端取消 global.Logger.WithFields(logger.Fields{ "requestId": requestId, "mac": mac, "mid": mid, "vender": vender, "sessionId": sessionId, }).Info("SpeechNluParseStream stream is canceled.") cancel() return nil } if err == io.EOF { global.Logger.WithFields(logger.Fields{ "requestId": requestId, "mac": mac, "mid": mid, "vender": vender, "sessionId": sessionId, }).Info("SpeechNluParseStream stream closed.") // 客户端关闭 } else { global.Logger.WithFields(logger.Fields{ "requestId": requestId, "mac": mac, "mid": mid, "vender": vender, "sessionId": sessionId, }).Errorf("SpeechNluParseStream stream.Recv error. %v", err) } cancel() return nil } requestBody, _ := json.Marshal(data) global.Logger.WithFields(logger.Fields{ "data": map[string]interface{}{ "speechNluParseStreamBody": string(requestBody), "query": data.Query, }, "requestId": requestId, "mac": mac, "mid": mid, "vender": vender, "sessionId": sessionId, }).Info("SpeechNluParseStream stream.Recv.") select { case <-cancelCtx.Done(): // 腾讯 ws 关闭了 return nil default: selfSemanticReq := TencentNluParseSemanticRequest2ModelSemanticReq(data) req := tencentNlu.TansTencentNlpWsReq(appKey, dsn, qua, auth, selfSemanticReq) speechNluWs.Send(req) tRequestBody, _ := json.Marshal(data) global.Logger.WithFields(logger.Fields{ "data": map[string]interface{}{ "speechNluParseStreamBody": string(tRequestBody), "query": data.Query, }, "requestId": requestId, "mac": mac, "mid": mid, "vender": vender, "sessionId": sessionId, }).Info("SpeechNluParseStream speechNluWs.Send.") } } }