algorithm/eas/easyrec_response.go (546 lines of code) (raw):
package eas
import (
"bytes"
json "encoding/json"
"fmt"
"strings"
"github.com/alibaba/pairec/v2/algorithm/eas/easyrec"
"github.com/alibaba/pairec/v2/algorithm/response"
"github.com/alibaba/pairec/v2/utils"
)
type EasyrecResponse struct {
RawFeatures string
GenerateFeatures *bytes.Buffer
ContextFeatures string
multiValModule bool
score float64
scoreArr map[string]float64
}
func (r *EasyrecResponse) GetScore() float64 {
return r.score
}
func (r *EasyrecResponse) GetScoreMap() map[string]float64 {
return r.scoreArr
}
func (r *EasyrecResponse) GetModuleType() bool {
return r.multiValModule
}
func easyrecMutValResponseFunc(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.PBResponse)
if !ok {
err = fmt.Errorf("easyrecMutValResponseFunc,invalid data type, %v", data)
return
}
outputs := resp.GetOutputs()
var response []map[string]float64
for _, itemId := range resp.ItemIds {
if result, ok := resp.Results[itemId]; ok {
scores := make(map[string]float64)
if len(outputs) == len(result.Scores) {
for k, score := range result.Scores {
scores[outputs[k]] = score
}
} else {
err = fmt.Errorf("outputs size is not equal scores")
return
}
response = append(response, scores)
} else {
scores := make(map[string]float64)
for _, out := range outputs {
scores[out] = float64(0)
}
response = append(response, scores)
}
}
for _, v := range response {
ret = append(ret, &EasyrecResponse{scoreArr: v, multiValModule: true})
}
return
}
func easyrecMutValResponseFuncDebug(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.PBResponse)
if !ok {
err = fmt.Errorf("invalid data type, %v", data)
return
}
outputs := resp.GetOutputs()
var response []map[string]float64
var (
itemFeatures []string
generateFeatures []*bytes.Buffer
contextFeatures []string
)
for _, itemId := range resp.ItemIds {
scores := make(map[string]float64)
for _, out := range outputs {
scores[out] = float64(0)
}
response = append(response, scores)
if f, ok := resp.RawFeatures[itemId]; ok {
itemFeatures = append(itemFeatures, f)
} else {
itemFeatures = append(itemFeatures, "")
}
if g, ok := resp.GenerateFeatures[itemId]; ok {
generateFeatures = append(generateFeatures, bytes.NewBufferString(g))
} else {
generateFeatures = append(generateFeatures, new(bytes.Buffer))
}
if c, ok := resp.ContextFeatures[itemId]; ok {
features := c.Features
j, _ := json.Marshal(features)
contextFeatures = append(contextFeatures, string(j))
} else {
contextFeatures = append(contextFeatures, "")
}
}
for i, v := range response {
ret = append(ret, &EasyrecResponse{scoreArr: v, multiValModule: true, RawFeatures: itemFeatures[i], GenerateFeatures: generateFeatures[i], ContextFeatures: contextFeatures[i]})
}
return
}
type EasyrecClassificationResponse struct {
EasyrecResponse
mulClassifyArr map[string][]float64
}
func (r *EasyrecClassificationResponse) GetClassifyMap() map[string][]float64 {
return r.mulClassifyArr
}
func easyrecMutClassificationResponseFunc(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.PBResponse)
if !ok {
err = fmt.Errorf("easyrecMutClassificationResponseFunc,invalid data type, %v", data)
return
}
var response []map[string][]float64
for i := range resp.ItemIds {
scores := make(map[string][]float64)
for output, arrayProto := range resp.GetTfOutputs() {
if len(arrayProto.ArrayShape.Dim) == 1 {
scores[output] = []float64{float64(arrayProto.GetFloatVal()[i])}
} else if len(arrayProto.ArrayShape.Dim) == 2 {
var arr []float64
d := int(arrayProto.ArrayShape.Dim[1])
for j := 0; j < d; j++ {
arr = append(arr, float64(arrayProto.GetFloatVal()[i*d+j]))
}
scores[output] = arr
}
}
response = append(response, scores)
}
for _, v := range response {
ret = append(ret, &EasyrecClassificationResponse{mulClassifyArr: v, EasyrecResponse: EasyrecResponse{multiValModule: false}})
}
return
}
func easyrecMutClassificationResponseFuncDebug(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.PBResponse)
if !ok {
err = fmt.Errorf("easyrecMutClassificationResponseFuncDebug, invalid data type, %v", data)
return
}
var response []map[string][]float64
for i := range resp.ItemIds {
scores := make(map[string][]float64)
for output, arrayProto := range resp.GetTfOutputs() {
if len(arrayProto.ArrayShape.Dim) == 1 {
scores[output] = []float64{float64(arrayProto.GetFloatVal()[i])}
} else if len(arrayProto.ArrayShape.Dim) == 2 {
var arr []float64
d := int(arrayProto.ArrayShape.Dim[1])
for j := 0; j < d; j++ {
arr = append(arr, float64(arrayProto.GetFloatVal()[i*d+j]))
}
scores[output] = arr
}
}
response = append(response, scores)
}
var (
itemFeatures []string
generateFeatures []*bytes.Buffer
contextFeatures []string
)
for _, itemId := range resp.ItemIds {
if f, ok := resp.RawFeatures[itemId]; ok {
itemFeatures = append(itemFeatures, f)
} else {
itemFeatures = append(itemFeatures, "")
}
if g, ok := resp.GenerateFeatures[itemId]; ok {
generateFeatures = append(generateFeatures, bytes.NewBufferString(g))
} else {
generateFeatures = append(generateFeatures, new(bytes.Buffer))
}
if c, ok := resp.ContextFeatures[itemId]; ok {
features := c.Features
j, _ := json.Marshal(features)
contextFeatures = append(contextFeatures, string(j))
} else {
contextFeatures = append(contextFeatures, "")
}
}
for i, v := range response {
ret = append(ret, &EasyrecClassificationResponse{
mulClassifyArr: v,
EasyrecResponse: EasyrecResponse{multiValModule: false, RawFeatures: itemFeatures[i],
GenerateFeatures: generateFeatures[i], ContextFeatures: contextFeatures[i]},
})
}
return
}
func easyrecResponseFunc(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.PBResponse)
if !ok {
err = fmt.Errorf("invalid data type, %v", data)
return
}
for _, itemId := range resp.ItemIds {
if results, ok := resp.Results[itemId]; ok {
ret = append(ret, &EasyrecResponse{score: results.Scores[0]})
} else {
ret = append(ret, &EasyrecResponse{score: float64(0)})
}
}
return
}
func easyrecResponseFuncDebug(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.PBResponse)
if !ok {
err = fmt.Errorf("invalid data type, %v", data)
return
}
for _, itemId := range resp.ItemIds {
itemFeatures := ""
generateFeatures := new(bytes.Buffer)
contextFeatures := ""
if f, ok := resp.RawFeatures[itemId]; ok {
itemFeatures = f
}
if g, ok := resp.GenerateFeatures[itemId]; ok {
generateFeatures.WriteString(g)
}
if c, ok := resp.ContextFeatures[itemId]; ok {
features := c.Features
j, _ := json.Marshal(features)
contextFeatures = string(j)
}
if results, ok := resp.Results[itemId]; ok {
ret = append(ret, &EasyrecResponse{score: results.Scores[0], RawFeatures: itemFeatures, GenerateFeatures: generateFeatures, ContextFeatures: contextFeatures})
} else {
ret = append(ret, &EasyrecResponse{score: float64(0), RawFeatures: itemFeatures, GenerateFeatures: generateFeatures, ContextFeatures: contextFeatures})
}
}
return
}
type EasyrecUserEmbResponse struct {
userEmb string
}
func (r *EasyrecUserEmbResponse) GetScore() float64 {
return 0
}
func (r *EasyrecUserEmbResponse) GetScoreMap() map[string]float64 {
return nil
}
func (r *EasyrecUserEmbResponse) GetModuleType() bool {
return false
}
func (r *EasyrecUserEmbResponse) GetUserEmb() string {
return r.userEmb
}
func easyrecUserEmbResponseFunc(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.PBResponse)
if !ok {
err = fmt.Errorf("invalid data type, %v", data)
return
}
for _, arrayProto := range resp.GetTfOutputs() {
if arrayProto.GetDtype() == easyrec.ArrayDataType_DT_STRING {
if len(arrayProto.GetStringVal()) > 0 {
ret = append(ret, &EasyrecUserEmbResponse{userEmb: string(arrayProto.GetStringVal()[0])})
return
}
}
}
return
}
type EmbeddingInfo struct {
ItemId string
Score float64
}
type EasyrecUserRealtimeEmbeddingResponse struct {
EmbeddingList []*EmbeddingInfo
UserEmbedding string
GenerateFeatures *bytes.Buffer
}
func (r *EasyrecUserRealtimeEmbeddingResponse) GetScore() float64 {
return 0
}
func (r *EasyrecUserRealtimeEmbeddingResponse) GetScoreMap() map[string]float64 {
return nil
}
func (r *EasyrecUserRealtimeEmbeddingResponse) GetModuleType() bool {
return false
}
func (r *EasyrecUserRealtimeEmbeddingResponse) GetEmbeddingList() []*EmbeddingInfo {
return r.EmbeddingList
}
func (r *EasyrecUserRealtimeEmbeddingResponse) GetUserEmbedding() string {
return r.UserEmbedding
}
func easyrecUserRealtimeEmbeddingResponseFunc(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.PBResponse)
if !ok {
err = fmt.Errorf("invalid data type, %v", data)
return
}
var embeddings []string
for _, output := range resp.TfOutputs {
for _, val := range output.FloatVal {
embeddings = append(embeddings, utils.ToString(val, ""))
}
}
response := &EasyrecUserRealtimeEmbeddingResponse{
UserEmbedding: strings.Join(embeddings, ","),
}
if len(resp.GenerateFeatures) > 0 {
generateFeatures := new(bytes.Buffer)
for _, v := range resp.GenerateFeatures {
generateFeatures.WriteString(v)
break
}
response.GenerateFeatures = generateFeatures
}
for itemid, result := range resp.Results {
response.EmbeddingList = append(response.EmbeddingList, &EmbeddingInfo{ItemId: itemid, Score: result.Scores[0]})
}
ret = append(ret, response)
return
}
type EasyrecUserRealtimeEmbeddingMindResponse struct {
DimSize int
DimLength int
UserEmbedding string
EmbeddingList []*EmbeddingInfo
GenerateFeatures *bytes.Buffer
}
func (r *EasyrecUserRealtimeEmbeddingMindResponse) GetScore() float64 {
return 0
}
func (r *EasyrecUserRealtimeEmbeddingMindResponse) GetScoreMap() map[string]float64 {
return nil
}
func (r *EasyrecUserRealtimeEmbeddingMindResponse) GetModuleType() bool {
return false
}
func (r *EasyrecUserRealtimeEmbeddingMindResponse) GetEmbeddingList() []*EmbeddingInfo {
return r.EmbeddingList
}
func (r *EasyrecUserRealtimeEmbeddingMindResponse) GetDimSize() int {
return r.DimSize
}
func (r *EasyrecUserRealtimeEmbeddingMindResponse) GetDimLength() int {
return r.DimLength
}
func (r *EasyrecUserRealtimeEmbeddingMindResponse) GetUserEmbedding() string {
return r.UserEmbedding
}
func easyrecUserRealtimeEmbeddingMindResponseFunc(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.PBResponse)
if !ok {
err = fmt.Errorf("invalid data type, %v", data)
return
}
itemIdOutput, itemIdok := resp.TfOutputs["match_item_ids"]
itemScoresOutput, itemScoreok := resp.TfOutputs["match_item_scores"]
response := &EasyrecUserRealtimeEmbeddingMindResponse{}
if itemIdok && itemScoreok {
dimLength := itemIdOutput.ArrayShape.Dim[0]
dimSize := itemIdOutput.ArrayShape.Dim[1]
embeddings := make([]*EmbeddingInfo, 0, dimLength*dimSize)
for _, val := range itemIdOutput.StringVal {
info := &EmbeddingInfo{
ItemId: string(val),
}
embeddings = append(embeddings, info)
}
for i, val := range itemScoresOutput.FloatVal {
embeddings[i].Score = float64(val)
}
response.DimLength = int(dimLength)
response.DimSize = int(dimSize)
response.EmbeddingList = embeddings
}
if userEmbOutput, ok := resp.TfOutputs["user_interests"]; ok {
size := int(userEmbOutput.ArrayShape.Dim[len(userEmbOutput.ArrayShape.Dim)-1])
var embeddings []string
var embeddingList []string
for i, val := range userEmbOutput.FloatVal {
embeddings = append(embeddings, utils.ToString(val, ""))
if (i+1)%size == 0 {
embeddingList = append(embeddingList, strings.Join(embeddings, ","))
embeddings = embeddings[:0]
}
}
response.UserEmbedding = strings.Join(embeddingList, "|")
}
if len(resp.GenerateFeatures) > 0 {
generateFeatures := new(bytes.Buffer)
for _, v := range resp.GenerateFeatures {
generateFeatures.WriteString(v)
break
}
response.GenerateFeatures = generateFeatures
}
ret = append(ret, response)
return
}
func torchrecMutValResponseFunc(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.TorchRecPBResponse)
if !ok {
err = fmt.Errorf("invalid data type, %v", data)
return
}
outputs := resp.GetMapOutputs()
var response []map[string]float64
for i := range resp.ItemIds {
scores := make(map[string]float64)
for output, arrayProto := range outputs {
if arrayProto.Dtype == easyrec.ArrayDataType_DT_FLOAT {
scores[output] = float64(arrayProto.FloatVal[i])
} else if arrayProto.Dtype == easyrec.ArrayDataType_DT_DOUBLE {
scores[output] = arrayProto.DoubleVal[i]
}
}
response = append(response, scores)
}
for _, v := range response {
ret = append(ret, &EasyrecResponse{scoreArr: v, multiValModule: true})
}
return
}
func torchrecMutValResponseFuncDebug(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.TorchRecPBResponse)
if !ok {
err = fmt.Errorf("invalid data type, %v", data)
return
}
outputs := resp.GetMapOutputs()
var response []map[string]float64
var (
itemFeatures []string
generateFeatures []*bytes.Buffer
)
for i, itemId := range resp.ItemIds {
scores := make(map[string]float64)
for output, arrayProto := range outputs {
if arrayProto.Dtype == easyrec.ArrayDataType_DT_FLOAT {
scores[output] = float64(arrayProto.FloatVal[i])
} else if arrayProto.Dtype == easyrec.ArrayDataType_DT_DOUBLE {
scores[output] = arrayProto.DoubleVal[i]
}
}
response = append(response, scores)
if f, ok := resp.RawFeatures[itemId]; ok {
itemFeatures = append(itemFeatures, f)
} else {
itemFeatures = append(itemFeatures, "")
}
if g, ok := resp.GenerateFeatures[itemId]; ok {
generateFeatures = append(generateFeatures, bytes.NewBufferString(g))
} else {
generateFeatures = append(generateFeatures, new(bytes.Buffer))
}
}
for i, v := range response {
ret = append(ret, &EasyrecResponse{scoreArr: v, multiValModule: true, RawFeatures: itemFeatures[i], GenerateFeatures: generateFeatures[i]})
}
return
}
type TorchrecEmbeddingResponse struct {
embeddings []float32
dimSize int
}
func (r *TorchrecEmbeddingResponse) GetScore() float64 {
return 0
}
func (r *TorchrecEmbeddingResponse) GetScoreMap() map[string]float64 {
return nil
}
func (r *TorchrecEmbeddingResponse) GetModuleType() bool {
return false
}
func (r *TorchrecEmbeddingResponse) GetEmbedding() []float32 {
return r.embeddings
}
func (r *TorchrecEmbeddingResponse) GetEmbeddingSize() int {
return r.dimSize
}
func torchrecEmbeddingResponseFunc(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.TorchRecPBResponse)
if !ok {
err = fmt.Errorf("invalid data type, %v", data)
return
}
outputs := resp.GetMapOutputs()
var embeddings []float32
var dimSize int
for _, arrayProto := range outputs {
if len(arrayProto.ArrayShape.Dim) >= 2 {
dimSize = int(arrayProto.ArrayShape.Dim[1])
}
if arrayProto.Dtype == easyrec.ArrayDataType_DT_FLOAT {
embeddings = append(embeddings, arrayProto.FloatVal...)
}
break
}
ret = append(ret, &TorchrecEmbeddingResponse{embeddings: embeddings, dimSize: dimSize})
return
}
type TorchrecEmbeddingItemsResponse struct {
EmbeddingItems []*EmbeddingInfo
}
func (r *TorchrecEmbeddingItemsResponse) GetScore() float64 {
return 0
}
func (r *TorchrecEmbeddingItemsResponse) GetScoreMap() map[string]float64 {
return nil
}
func (r *TorchrecEmbeddingItemsResponse) GetModuleType() bool {
return false
}
func (r *TorchrecEmbeddingItemsResponse) GetEmbeddingItems() []*EmbeddingInfo {
return r.EmbeddingItems
}
func torchrecEmbeddingItemsResponseFunc(data interface{}) (ret []response.AlgoResponse, err error) {
resp, ok := data.(*easyrec.TorchRecPBResponse)
if !ok {
err = fmt.Errorf("invalid data type, %v", data)
return
}
outputs := resp.GetMapOutputs()
var embeddingItems []*EmbeddingInfo
var dimSize int
itemScoresOutput, itemScoreok := outputs["match_item_scores"]
if itemScoreok {
if len(itemScoresOutput.ArrayShape.Dim) >= 2 {
dimSize = int(itemScoresOutput.ArrayShape.Dim[1])
}
embeddingItems = make([]*EmbeddingInfo, 0, dimSize)
}
for i, itemId := range resp.ItemIds {
info := EmbeddingInfo{
ItemId: itemId,
}
if itemScoresOutput.Dtype == easyrec.ArrayDataType_DT_FLOAT {
info.Score = float64(itemScoresOutput.FloatVal[i])
} else if itemScoresOutput.Dtype == easyrec.ArrayDataType_DT_DOUBLE {
info.Score = itemScoresOutput.DoubleVal[i]
}
embeddingItems = append(embeddingItems, &info)
}
ret = append(ret, &TorchrecEmbeddingItemsResponse{EmbeddingItems: embeddingItems})
return
}