package services import ( "code.tczkiot.com/wlw/ai-agent/internal/models" "code.tczkiot.com/wlw/ai-agent/internal/pkg/enums" "code.tczkiot.com/wlw/ai-agent/internal/pkg/errorsx" "code.tczkiot.com/wlw/ai-agent/internal/services/storage" "encoding/json" "strings" ) type imMessageAssetPayload struct { AssetID string `json:"asset_id,omitempty"` Provider enums.AssetProvider `json:"provider,omitempty"` StorageKey string `json:"storage_key,omitempty"` Filename string `json:"filename,omitempty"` FileSize int64 `json:"file_size,omitempty"` MimeType string `json:"mime_type,omitempty"` URL string `json:"url,omitempty"` Assets []imMessageAssetPayload `json:"assets,omitempty"` } func (p *imMessageAssetPayload) items() []*imMessageAssetPayload { if p == nil { return nil } if len(p.Assets) == 0 { return []*imMessageAssetPayload{p} } items := make([]*imMessageAssetPayload, 0, len(p.Assets)) for index := range p.Assets { items = append(items, &p.Assets[index]) } return items } func parseIMMessageAssetPayload(payload string) (*imMessageAssetPayload, error) { payload = strings.TrimSpace(payload) if payload == "" { return nil, errorsx.InvalidParamI18n("error.e0346") } ret := &imMessageAssetPayload{} if err := json.Unmarshal([]byte(payload), ret); err != nil { return nil, errorsx.InvalidParamI18n("error.e0344") } items := ret.items() if len(items) == 0 || len(items) > 9 { return nil, errorsx.InvalidParamI18n("error.e0345") } for _, item := range items { item.AssetID = strings.TrimSpace(item.AssetID) item.Provider = enums.AssetProvider(strings.TrimSpace(string(item.Provider))) item.StorageKey = strings.TrimSpace(item.StorageKey) if item.AssetID == "" { return nil, errorsx.InvalidParamI18n("error.e0345") } } return ret, nil } func buildIMMessageAssetPayload(asset *models.Asset) (string, error) { if asset == nil { return "", errorsx.InvalidParamI18n("error.e0342") } payload, err := json.Marshal(imMessageAssetPayload{ AssetID: asset.AssetID, Provider: asset.Provider, StorageKey: asset.StorageKey, Filename: asset.Filename, FileSize: asset.FileSize, MimeType: asset.MimeType, }) if err != nil { return "", err } return string(payload), nil } func buildIMMessageAssetBatchPayload(assets []*models.Asset) (string, error) { if len(assets) == 0 || len(assets) > 9 { return "", errorsx.InvalidParamI18n("error.e0342") } payload := imMessageAssetPayload{Assets: make([]imMessageAssetPayload, 0, len(assets))} for _, asset := range assets { if asset == nil { return "", errorsx.InvalidParamI18n("error.e0342") } payload.Assets = append(payload.Assets, imMessageAssetPayload{ AssetID: asset.AssetID, Provider: asset.Provider, StorageKey: asset.StorageKey, Filename: asset.Filename, FileSize: asset.FileSize, MimeType: asset.MimeType, }) } data, err := json.Marshal(payload) if err != nil { return "", err } return string(data), nil } func buildIMMessageAssetPayloadForResponse(payload string) string { assetPayload, err := parseIMMessageAssetPayload(payload) if err != nil { return strings.TrimSpace(payload) } for _, item := range assetPayload.items() { hydrateIMMessageAssetPayload(item) if item.Provider != "" && item.StorageKey != "" { if provider, err := storage.NewProvider(item.Provider); err == nil { item.URL = provider.GetSignedURL(item.StorageKey) } } } data, err := json.Marshal(assetPayload) if err != nil { return strings.TrimSpace(payload) } return string(data) } func hydrateIMMessageAssetPayload(payload *imMessageAssetPayload) *imMessageAssetPayload { if payload == nil { return nil } if payload.Provider != "" && payload.StorageKey != "" { return payload } if payload.AssetID == "" { return payload } asset := AssetService.GetByAssetID(payload.AssetID) if asset == nil { return payload } if payload.Provider == "" { payload.Provider = asset.Provider } if payload.StorageKey == "" { payload.StorageKey = strings.TrimSpace(asset.StorageKey) } if payload.Filename == "" { payload.Filename = strings.TrimSpace(asset.Filename) } if payload.FileSize <= 0 { payload.FileSize = asset.FileSize } if payload.MimeType == "" { payload.MimeType = strings.TrimSpace(asset.MimeType) } return payload } func validateConversationAsset(asset *models.Asset, conversationID int64, messageType enums.IMMessageType) error { if asset == nil { return errorsx.InvalidParamI18n("error.e0342") } if asset.Status != enums.AssetStatusSuccess { return errorsx.InvalidParamI18n("error.e0343") } if conversationID <= 0 || asset.ConversationID != conversationID { // Deliberately use the same error as a missing asset so callers cannot // probe whether an asset belongs to another customer's conversation. return errorsx.InvalidParamI18n("error.e0342") } if messageType == enums.IMMessageTypeImage && !isSupportedVisionImageMIME(asset.MimeType) { return errorsx.InvalidParamI18n("error.e0090") } return nil }