feat: 增加标签相关 api
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
cjy 2025-12-17 14:39:14 +08:00
parent f923429b96
commit cff74a8319
9 changed files with 2482 additions and 202 deletions

View File

@ -16,6 +16,7 @@ type AyrshareProvider struct {
aryshareMessageLogic logic.IAryshareMessage aryshareMessageLogic logic.IAryshareMessage
aryshareCommentLogic logic.IAryshareComment aryshareCommentLogic logic.IAryshareComment
aryshareAnalyticsLogic logic.IAryshareAnalytics aryshareAnalyticsLogic logic.IAryshareAnalytics
aryshareTagLogic logic.IAryshareTag
} }
// NewAyrshareProvider 创建 AyrshareProvider 实例 // NewAyrshareProvider 创建 AyrshareProvider 实例
@ -28,6 +29,7 @@ func NewAyrshareProvider() *AyrshareProvider {
aryshareMessageLogic: &logic.AyrshareMessage{}, aryshareMessageLogic: &logic.AyrshareMessage{},
aryshareCommentLogic: &logic.AyrshareComment{}, aryshareCommentLogic: &logic.AyrshareComment{},
aryshareAnalyticsLogic: &logic.AyrshareAnalytics{}, aryshareAnalyticsLogic: &logic.AyrshareAnalytics{},
aryshareTagLogic: &logic.AyrshareTag{},
} }
} }

View File

@ -0,0 +1,174 @@
package controller
import (
"context"
"micro-ayrshare/internal/dto"
"micro-ayrshare/pb/aryshare"
)
// AutoHashtags 自动为帖子添加合适的标签
// 将 proto 请求转换为 DTO调用 logic 层,然后再组装回 proto 响应。
func (a *AyrshareProvider) AutoHashtags(_ context.Context, req *aryshare.AutoHashtagsRequest) (res *aryshare.AutoHashtagsResponse, err error) {
res = new(aryshare.AutoHashtagsResponse)
// 组装 DTO 请求
dtoReq := &dto.AutoHashtagsRequest{
Post: req.Post,
Position: req.Position,
Language: req.Language,
ProfileKey: req.ProfileKey,
}
if req.Max != 0 {
max := int(req.Max)
dtoReq.Max = &max
}
// 调用 logic 层
dtoRes, err := a.aryshareTagLogic.AutoHashtags(dtoReq)
if err != nil {
return nil, err
}
// 组装 proto 响应
res.Post = dtoRes.Post
res.Action = dtoRes.Action
res.Status = dtoRes.Status
res.Code = int32(dtoRes.Code)
res.Message = dtoRes.Message
return
}
// CheckBannedHashtag 查看某个标签是否被平台禁用
func (a *AyrshareProvider) CheckBannedHashtag(_ context.Context, req *aryshare.CheckBannedHashtagRequest) (res *aryshare.CheckBannedHashtagResponse, err error) {
res = new(aryshare.CheckBannedHashtagResponse)
// 组装 DTO 请求
dtoReq := &dto.CheckBannedHashtagRequest{
Hashtag: req.Hashtag,
ProfileKey: req.ProfileKey,
}
// 调用 logic 层
dtoRes, err := a.aryshareTagLogic.CheckBannedHashtag(dtoReq)
if err != nil {
return nil, err
}
// 组装 proto 响应
res.Hashtag = dtoRes.Hashtag
res.Banned = dtoRes.Banned
res.Action = dtoRes.Action
res.Status = dtoRes.Status
res.Code = int32(dtoRes.Code)
res.Message = dtoRes.Message
return
}
// RecommendHashtags 根据关键字推荐热门标签
func (a *AyrshareProvider) RecommendHashtags(_ context.Context, req *aryshare.RecommendHashtagsRequest) (res *aryshare.RecommendHashtagsResponse, err error) {
res = new(aryshare.RecommendHashtagsResponse)
// 组装 DTO 请求
dtoReq := &dto.RecommendHashtagsRequest{
Keyword: req.Keyword,
ProfileKey: req.ProfileKey,
}
// 调用 logic 层
dtoRes, err := a.aryshareTagLogic.RecommendHashtags(dtoReq)
if err != nil {
return nil, err
}
// 组装 proto 响应
res.Keyword = dtoRes.Keyword
res.Action = dtoRes.Action
res.Status = dtoRes.Status
res.Code = int32(dtoRes.Code)
res.Message = dtoRes.Message
// 转换推荐列表
if len(dtoRes.Recommendations) > 0 {
res.Recommendations = make([]*aryshare.HashtagRecommendation, 0, len(dtoRes.Recommendations))
for _, r := range dtoRes.Recommendations {
res.Recommendations = append(res.Recommendations, &aryshare.HashtagRecommendation{
ViewCount: r.ViewCount,
Name: r.Name,
})
}
}
return
}
// SearchHashtags 搜索话题标签,返回对应的 Instagram 媒体数据
func (a *AyrshareProvider) SearchHashtags(_ context.Context, req *aryshare.SearchHashtagsRequest) (res *aryshare.SearchHashtagsResponse, err error) {
res = new(aryshare.SearchHashtagsResponse)
// 组装 DTO 请求
dtoReq := &dto.SearchHashtagsRequest{
Keyword: req.Keyword,
SearchType: req.SearchType,
ProfileKey: req.ProfileKey,
}
// 调用 logic 层
dtoRes, err := a.aryshareTagLogic.SearchHashtags(dtoReq)
if err != nil {
return nil, err
}
// 组装 proto 响应
res.Status = dtoRes.Status
res.Count = int32(dtoRes.Count)
res.LastUpdated = dtoRes.LastUpdated
res.NextUpdate = dtoRes.NextUpdate
res.Action = dtoRes.Action
res.Code = int32(dtoRes.ErrorCode)
res.Message = dtoRes.Message
// 转换 hashtag 基本信息
if dtoRes.Hashtag != nil {
res.Hashtag = &aryshare.SearchHashtagInfo{
Id: dtoRes.Hashtag.ID,
Name: dtoRes.Hashtag.Name,
}
}
// 转换 searchResults 列表
if len(dtoRes.SearchResults) > 0 {
res.SearchResults = make([]*aryshare.SearchHashtagMedia, 0, len(dtoRes.SearchResults))
for _, media := range dtoRes.SearchResults {
protoMedia := &aryshare.SearchHashtagMedia{
Caption: media.Caption,
CommentsCount: int32(media.CommentsCount),
Id: media.ID,
LikeCount: int32(media.LikeCount),
MediaType: media.MediaType,
MediaUrl: media.MediaUrl,
Permalink: media.Permalink,
Timestamp: media.Timestamp,
}
// 转换 children
if media.Children != nil && len(media.Children.Data) > 0 {
children := &aryshare.SearchHashtagChildren{
Data: make([]*aryshare.SearchHashtagChild, 0, len(media.Children.Data)),
}
for _, child := range media.Children.Data {
children.Data = append(children.Data, &aryshare.SearchHashtagChild{
Id: child.ID,
})
}
protoMedia.Children = children
}
res.SearchResults = append(res.SearchResults, protoMedia)
}
}
return
}

View File

@ -0,0 +1,125 @@
package dto
// AutoHashtagsRequest 自动生成标签请求参数
// 对应 Ayrshare 接口文档: https://www.ayrshare.com/docs/apis/hashtags/auto-hashtags
type AutoHashtagsRequest struct {
Post string `json:"post"` // 必填,原始帖子内容,最大长度 1000 字符
Max *int `json:"max,omitempty"` // 可选生成的最大标签数量1-10默认 2
Position string `json:"position,omitempty"` // 可选,标签插入位置,例如 "auto"
Language string `json:"language,omitempty"` // 可选,帖子语言代码,例如 "en"、"fr"
ProfileKey string `json:"-"` // 可选,多用户场景下的 Profile Key通过请求头传递
}
// AutoHashtagsResponse 自动生成标签返回结果
// 正常情况仅返回替换后的 post出错时返回 action/status/code/message
// 参考 internal/dto/自动标签返回参数.md
type AutoHashtagsResponse struct {
Post string `json:"post,omitempty"` // 自动补全标签后的帖子内容
// 错误相关字段(当调用失败时会返回)
Action string `json:"action,omitempty"`
Status string `json:"status,omitempty"`
Code int `json:"code,omitempty"`
Message string `json:"message,omitempty"`
}
// CheckBannedHashtagRequest 查看被禁用标签请求
// 对应 Ayrshare 接口文档: https://www.ayrshare.com/docs/apis/hashtags/check-hashtags
type CheckBannedHashtagRequest struct {
Hashtag string `json:"-"` // 必填,要检查的标签,例如 "bikinibody" 或 "#bikinibody"
ProfileKey string `json:"-"` // 可选,多用户场景下的 Profile Key通过请求头传递
}
// CheckBannedHashtagResponse 查看被禁用标签返回结果
// 参考 internal/dto/查看被禁用的标签返回参数.md
type CheckBannedHashtagResponse struct {
Hashtag string `json:"hashtag,omitempty"` // 请求的标签
Banned bool `json:"banned,omitempty"` // 是否被禁用
// 出错时的通用返回结构
Action string `json:"action,omitempty"`
Status string `json:"status,omitempty"`
Code int `json:"code,omitempty"`
Message string `json:"message,omitempty"`
}
// HashtagRecommendation 单条推荐标签信息
// 对应 Ayrshare Recommend Hashtags 返回中的 recommendations 数组元素
type HashtagRecommendation struct {
ViewCount int64 `json:"viewCount"` // 推荐标签在 TikTok 上的浏览次数
Name string `json:"name"` // 推荐的标签名称(不带 #
}
// RecommendHashtagsRequest 推荐话题标签请求
// 对应 Ayrshare 接口文档: https://www.ayrshare.com/docs/apis/hashtags/recommend-hashtags
type RecommendHashtagsRequest struct {
Keyword string `json:"-"` // 必填,单个关键字,例如 "apple"
ProfileKey string `json:"-"` // 可选,多用户场景下的 Profile Key通过请求头传递
}
// RecommendHashtagsResponse 推荐话题标签返回结果
// 参考 internal/dto/推荐话话题返回参数.md
type RecommendHashtagsResponse struct {
Keyword string `json:"keyword,omitempty"` // 请求时的关键字
Recommendations []HashtagRecommendation `json:"recommendations,omitempty"` // 推荐的标签列表
// 出错时的通用返回结构
Action string `json:"action,omitempty"`
Status string `json:"status,omitempty"`
Code int `json:"code,omitempty"`
Message string `json:"message,omitempty"`
}
// SearchHashtagsRequest 搜索话题标签请求
// 对应 Ayrshare 接口文档: https://www.ayrshare.com/docs/apis/hashtags/search-hashtags
type SearchHashtagsRequest struct {
Keyword string `json:"-"` // 必填,要搜索的关键字,例如 "wisdom"
SearchType string `json:"-"` // 可选搜索类型top 或 recent不传则使用服务端默认 top
ProfileKey string `json:"-"` // 可选,多用户场景下的 Profile Key通过请求头传递
}
// SearchHashtagInfo 单个话题标签的基本信息
type SearchHashtagInfo struct {
ID string `json:"id"` // Hashtag ID
Name string `json:"name"` // Hashtag 名称,例如 "wisdom"
}
// SearchHashtagChild 搜索结果中 children.data 的元素
type SearchHashtagChild struct {
ID string `json:"id"`
}
// SearchHashtagChildren 搜索结果中的 children 对象
type SearchHashtagChildren struct {
Data []SearchHashtagChild `json:"data,omitempty"`
}
// SearchHashtagMedia 搜索结果中的单条 Instagram 媒体信息
// 参考 internal/dto/搜索话题标签返回参数.md
type SearchHashtagMedia struct {
Caption string `json:"caption"` // 媒体文案
Children *SearchHashtagChildren `json:"children,omitempty"` // 多图时的子媒体 ID 列表
CommentsCount int `json:"commentsCount"` // 评论数
ID string `json:"id"` // 媒体 ID
LikeCount int `json:"likeCount"` // 点赞数
MediaType string `json:"mediaType"` // 媒体类型,例如 CAROUSEL_ALBUM
MediaUrl string `json:"mediaUrl"` // 媒体封面 URL
Permalink string `json:"permalink"` // Instagram 详情页链接
Timestamp string `json:"timestamp"` // 发布时间
}
// SearchHashtagsResponse 搜索话题标签响应
// 参考 internal/dto/搜索话题标签返回参数.md
type SearchHashtagsResponse struct {
Status string `json:"status,omitempty"` // 请求状态success 或 error
Hashtag *SearchHashtagInfo `json:"hashtag,omitempty"` // 命中的 hashtag 信息
SearchResults []SearchHashtagMedia `json:"searchResults,omitempty"` // 搜索结果媒体列表
Count int `json:"count,omitempty"` // 返回结果条数
LastUpdated string `json:"lastUpdated,omitempty"` // 最后更新时间
NextUpdate string `json:"nextUpdate,omitempty"` // 下次更新时间
// 出错时的通用返回结构(情况二)
Action string `json:"action,omitempty"`
ErrorCode int `json:"code,omitempty"` // 错误码,为避免与正常字段冲突,这里使用不同的结构字段名
Message string `json:"message,omitempty"`
}

View File

@ -0,0 +1,318 @@
package logic
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
errCommon "micro-ayrshare/pkg/err"
"micro-ayrshare/pkg/msg"
"micro-ayrshare/internal/dto"
"micro-ayrshare/pkg/app"
"micro-ayrshare/pkg/utils"
)
// IAryshareTag Hashtags 相关业务接口
// 封装 Ayrshare 的自动标签 / 禁用标签检查 / 推荐标签 / 搜索标签 四个接口
type IAryshareTag interface {
// AutoHashtags 自动为帖子添加合适的标签
AutoHashtags(req *dto.AutoHashtagsRequest) (res *dto.AutoHashtagsResponse, err error)
// CheckBannedHashtag 检查单个标签是否被社交平台禁用
CheckBannedHashtag(req *dto.CheckBannedHashtagRequest) (res *dto.CheckBannedHashtagResponse, err error)
// RecommendHashtags 根据关键字推荐热门标签
RecommendHashtags(req *dto.RecommendHashtagsRequest) (res *dto.RecommendHashtagsResponse, err error)
// SearchHashtags 搜索话题标签并返回相关媒体
SearchHashtags(req *dto.SearchHashtagsRequest) (res *dto.SearchHashtagsResponse, err error)
}
// AyrshareTag Hashtags 相关逻辑实现
type AyrshareTag struct {
}
// AutoHashtags 自动为帖子添加合适的标签
// 文档: https://www.ayrshare.com/docs/apis/hashtags/auto-hashtags
func (a *AyrshareTag) AutoHashtags(req *dto.AutoHashtagsRequest) (res *dto.AutoHashtagsResponse, err error) {
errCommon.NoReturnInfo(req, "自动生成标签 参数信息: ")
res = new(dto.AutoHashtagsResponse)
// 基本参数校验post 不能为空,其它参数交给 Ayrshare 校验,便于兼容后续扩展
if req.Post == "" {
return nil, errCommon.ReturnError(
fmt.Errorf(msg.ErrPostContentEmpty),
msg.ErrPostContentEmpty,
"自动生成标签 失败: ",
)
}
// 构建请求 URL
urlStr := fmt.Sprintf("%s/api/hashtags/auto", app.ModuleClients.AryshareClient.Config.Endpoint)
// 准备请求体ProfileKey 使用请求头传递,因此结构体中使用 json:\"-\" 排除)
reqBody, err := json.Marshal(req)
if err != nil {
return nil, errCommon.ReturnError(err, msg.ErrorJSONMarshal, "自动生成标签失败: ")
}
// 准备请求头
headers := make(map[string]string)
headers["Authorization"] = fmt.Sprintf("Bearer %s", app.ModuleClients.AryshareClient.Config.ApiKey)
if req.ProfileKey != "" {
headers["Profile-Key"] = req.ProfileKey
}
// 发起 HTTP 请求
statusCode, result, err := utils.PostWithHeaders(urlStr, reqBody, headers)
if err != nil {
return nil, errCommon.ReturnError(err, msg.ErrorAutoHashtagsFailed, "自动生成标签失败: ")
}
// 解析响应
var autoResp dto.AutoHashtagsResponse
if err := json.Unmarshal([]byte(result), &autoResp); err != nil {
return nil, errCommon.ReturnError(err, msg.ErrorJSONParse, "自动生成标签失败: ")
}
// Ayrshare 文档未明确错误时的 HTTP 状态码,这里统一按照:
// - 200 且未返回 status=error 视为成功
// - 其它情况视为失败,并优先使用返回的 message/code 作为错误信息
if statusCode != http.StatusOK || autoResp.Status == "error" {
errMsg := autoResp.Message
if errMsg == "" {
errMsg = msg.ErrorAutoHashtagsFailed
}
if autoResp.Code != 0 {
errMsg = fmt.Sprintf("错误代码: %d, %s", autoResp.Code, errMsg)
}
return nil, errCommon.ReturnError(
fmt.Errorf("接口返回状态码: %d, 错误信息: %s, 响应结果: %s", statusCode, errMsg, result),
errMsg,
"自动生成标签 失败: ",
)
}
errCommon.NoReturnInfo(&autoResp, "自动生成标签 成功: ")
res = &autoResp
return
}
// CheckBannedHashtag 检查单个标签是否被社交平台禁用
// 文档: https://www.ayrshare.com/docs/apis/hashtags/check-hashtags
func (a *AyrshareTag) CheckBannedHashtag(req *dto.CheckBannedHashtagRequest) (res *dto.CheckBannedHashtagResponse, err error) {
errCommon.NoReturnInfo(req, "查看被禁用的标签 参数信息: ")
res = new(dto.CheckBannedHashtagResponse)
// 基本参数校验hashtag 不能为空
if req.Hashtag == "" {
return nil, errCommon.ReturnError(
fmt.Errorf(msg.ErrHashtagEmpty),
msg.ErrHashtagEmpty,
"查看被禁用的标签 失败: ",
)
}
// 构建请求 URL 和查询参数
baseURL := fmt.Sprintf("%s/api/hashtags/banned", app.ModuleClients.AryshareClient.Config.Endpoint)
u, err := url.Parse(baseURL)
if err != nil {
return nil, errCommon.ReturnError(err, msg.ErrorParseURL, "查看被禁用的标签 失败: ")
}
q := u.Query()
// Ayrshare 支持传入 "hashtag" 或 "#hashtag",这里直接透传,由底层接口校验
q.Set("hashtag", req.Hashtag)
u.RawQuery = q.Encode()
fullURL := u.String()
// 准备请求头
headers := make(map[string]string)
headers["Authorization"] = fmt.Sprintf("Bearer %s", app.ModuleClients.AryshareClient.Config.ApiKey)
if req.ProfileKey != "" {
headers["Profile-Key"] = req.ProfileKey
}
// 发起 HTTP 请求
statusCode, result, err := utils.GetWithHeaders(fullURL, headers)
if err != nil {
return nil, errCommon.ReturnError(err, msg.ErrorCheckBannedHashtagsFailed, "查看被禁用的标签失败: ")
}
// 解析响应无论成功还是失败Ayrshare 都会返回 JSON
var bannedResp dto.CheckBannedHashtagResponse
if err := json.Unmarshal([]byte(result), &bannedResp); err != nil {
return nil, errCommon.ReturnError(err, msg.ErrorJSONParse, "查看被禁用的标签失败: ")
}
// 根据文档:
// - 200成功返回 { "hashtag": "...", "banned": true/false }
// - 400参数错误返回 { "action": "request", "status": "error", "code": 101, "message": "..." }
if statusCode != http.StatusOK || bannedResp.Status == "error" {
errMsg := bannedResp.Message
if errMsg == "" {
errMsg = msg.ErrorCheckBannedHashtagsFailed
}
if bannedResp.Code != 0 {
errMsg = fmt.Sprintf("错误代码: %d, %s", bannedResp.Code, errMsg)
}
return nil, errCommon.ReturnError(
fmt.Errorf("接口返回状态码: %d, 错误信息: %s, 响应结果: %s", statusCode, errMsg, result),
errMsg,
"查看被禁用的标签 失败: ",
)
}
errCommon.NoReturnInfo(&bannedResp, "查看被禁用的标签 成功: ")
res = &bannedResp
return
}
// RecommendHashtags 根据关键字推荐热门标签
// 文档: https://www.ayrshare.com/docs/apis/hashtags/recommend-hashtags
func (a *AyrshareTag) RecommendHashtags(req *dto.RecommendHashtagsRequest) (res *dto.RecommendHashtagsResponse, err error) {
errCommon.NoReturnInfo(req, "推荐话题标签 参数信息: ")
res = new(dto.RecommendHashtagsResponse)
// 基本参数校验keyword 不能为空
if req.Keyword == "" {
return nil, errCommon.ReturnError(
fmt.Errorf(msg.ErrKeywordEmpty),
msg.ErrKeywordEmpty,
"推荐话题标签 失败: ",
)
}
// 构建请求 URL 和查询参数
baseURL := fmt.Sprintf("%s/api/hashtags/recommend", app.ModuleClients.AryshareClient.Config.Endpoint)
u, err := url.Parse(baseURL)
if err != nil {
return nil, errCommon.ReturnError(err, msg.ErrorParseURL, "推荐话题标签 失败: ")
}
q := u.Query()
q.Set("keyword", req.Keyword)
u.RawQuery = q.Encode()
fullURL := u.String()
// 准备请求头
headers := make(map[string]string)
headers["Authorization"] = fmt.Sprintf("Bearer %s", app.ModuleClients.AryshareClient.Config.ApiKey)
if req.ProfileKey != "" {
headers["Profile-Key"] = req.ProfileKey
}
// 发起 HTTP 请求
statusCode, result, err := utils.GetWithHeaders(fullURL, headers)
if err != nil {
return nil, errCommon.ReturnError(err, msg.ErrorRecommendHashtagsFailed, "推荐话题标签失败: ")
}
// 解析响应
var recommendResp dto.RecommendHashtagsResponse
if err := json.Unmarshal([]byte(result), &recommendResp); err != nil {
return nil, errCommon.ReturnError(err, msg.ErrorJSONParse, "推荐话题标签失败: ")
}
// 根据文档:
// - 200成功返回 keyword + recommendations
// - 400缺少 keyword返回错误结构
if statusCode != http.StatusOK || recommendResp.Status == "error" {
errMsg := recommendResp.Message
if errMsg == "" {
errMsg = msg.ErrorRecommendHashtagsFailed
}
if recommendResp.Code != 0 {
errMsg = fmt.Sprintf("错误代码: %d, %s", recommendResp.Code, errMsg)
}
return nil, errCommon.ReturnError(
fmt.Errorf("接口返回状态码: %d, 错误信息: %s, 响应结果: %s", statusCode, errMsg, result),
errMsg,
"推荐话题标签 失败: ",
)
}
errCommon.NoReturnInfo(&recommendResp, "推荐话题标签 成功: ")
res = &recommendResp
return
}
// SearchHashtags 搜索话题标签并返回相关媒体
// 文档: https://www.ayrshare.com/docs/apis/hashtags/search-hashtags
func (a *AyrshareTag) SearchHashtags(req *dto.SearchHashtagsRequest) (res *dto.SearchHashtagsResponse, err error) {
errCommon.NoReturnInfo(req, "搜索话题标签 参数信息: ")
res = new(dto.SearchHashtagsResponse)
// 基本参数校验keyword 不能为空
if req.Keyword == "" {
return nil, errCommon.ReturnError(
fmt.Errorf(msg.ErrKeywordEmpty),
msg.ErrKeywordEmpty,
"搜索话题标签 失败: ",
)
}
// 构建请求 URL 和查询参数
baseURL := fmt.Sprintf("%s/api/hashtags/search", app.ModuleClients.AryshareClient.Config.Endpoint)
u, err := url.Parse(baseURL)
if err != nil {
return nil, errCommon.ReturnError(err, msg.ErrorParseURL, "搜索话题标签 失败: ")
}
q := u.Query()
q.Set("keyword", req.Keyword)
// searchType 可选,默认 top这里仅在调用方传入时追加
if req.SearchType != "" {
q.Set("searchType", req.SearchType)
}
u.RawQuery = q.Encode()
fullURL := u.String()
// 准备请求头
headers := make(map[string]string)
headers["Authorization"] = fmt.Sprintf("Bearer %s", app.ModuleClients.AryshareClient.Config.ApiKey)
if req.ProfileKey != "" {
headers["Profile-Key"] = req.ProfileKey
}
// 发起 HTTP 请求
statusCode, result, err := utils.GetWithHeaders(fullURL, headers)
if err != nil {
return nil, errCommon.ReturnError(err, msg.ErrorSearchHashtagsFailed, "搜索话题标签失败: ")
}
// 解析响应
var searchResp dto.SearchHashtagsResponse
if err := json.Unmarshal([]byte(result), &searchResp); err != nil {
return nil, errCommon.ReturnError(err, msg.ErrorJSONParse, "搜索话题标签失败: ")
}
// 根据文档:
// - 200成功返回 status: success + hashtag + searchResults
// - 400Bad Request返回 status: error + action/code/message
if statusCode != http.StatusOK || searchResp.Status == "error" {
errMsg := searchResp.Message
if errMsg == "" {
errMsg = msg.ErrorSearchHashtagsFailed
}
if searchResp.ErrorCode != 0 {
errMsg = fmt.Sprintf("错误代码: %d, %s", searchResp.ErrorCode, errMsg)
}
return nil, errCommon.ReturnError(
fmt.Errorf("接口返回状态码: %d, 错误信息: %s, 响应结果: %s", statusCode, errMsg, result),
errMsg,
"搜索话题标签 失败: ",
)
}
errCommon.NoReturnInfo(&searchResp, "搜索话题标签 成功: ")
res = &searchResp
return
}

File diff suppressed because it is too large Load Diff

View File

@ -816,3 +816,85 @@ func (this *GetSocialAnalyticsRequest) Validate() error {
func (this *GetSocialAnalyticsResponse) Validate() error { func (this *GetSocialAnalyticsResponse) Validate() error {
return nil return nil
} }
func (this *AutoHashtagsRequest) Validate() error {
if this.Post == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Post", fmt.Errorf(`post内容不能为空`))
}
return nil
}
func (this *AutoHashtagsResponse) Validate() error {
return nil
}
func (this *CheckBannedHashtagRequest) Validate() error {
if this.Hashtag == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Hashtag", fmt.Errorf(`hashtag不能为空`))
}
return nil
}
func (this *CheckBannedHashtagResponse) Validate() error {
return nil
}
func (this *HashtagRecommendation) Validate() error {
return nil
}
func (this *RecommendHashtagsRequest) Validate() error {
if this.Keyword == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Keyword", fmt.Errorf(`keyword不能为空`))
}
return nil
}
func (this *RecommendHashtagsResponse) Validate() error {
for _, item := range this.Recommendations {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Recommendations", err)
}
}
}
return nil
}
func (this *SearchHashtagsRequest) Validate() error {
if this.Keyword == "" {
return github_com_mwitkow_go_proto_validators.FieldError("Keyword", fmt.Errorf(`keyword不能为空`))
}
return nil
}
func (this *SearchHashtagInfo) Validate() error {
return nil
}
func (this *SearchHashtagChild) Validate() error {
return nil
}
func (this *SearchHashtagChildren) Validate() error {
for _, item := range this.Data {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Data", err)
}
}
}
return nil
}
func (this *SearchHashtagMedia) Validate() error {
if this.Children != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Children); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Children", err)
}
}
return nil
}
func (this *SearchHashtagsResponse) Validate() error {
if this.Hashtag != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Hashtag); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("Hashtag", err)
}
}
for _, item := range this.SearchResults {
if item != nil {
if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil {
return github_com_mwitkow_go_proto_validators.FieldError("SearchResults", err)
}
}
}
return nil
}

View File

@ -53,6 +53,11 @@ type AyrshareClient interface {
GetPostAnalytics(ctx context.Context, in *GetPostAnalyticsRequest, opts ...grpc_go.CallOption) (*GetPostAnalyticsResponse, common.ErrorWithAttachment) GetPostAnalytics(ctx context.Context, in *GetPostAnalyticsRequest, opts ...grpc_go.CallOption) (*GetPostAnalyticsResponse, common.ErrorWithAttachment)
GetPostAnalyticsBySocialID(ctx context.Context, in *GetPostAnalyticsBySocialIDRequest, opts ...grpc_go.CallOption) (*GetPostAnalyticsResponse, common.ErrorWithAttachment) GetPostAnalyticsBySocialID(ctx context.Context, in *GetPostAnalyticsBySocialIDRequest, opts ...grpc_go.CallOption) (*GetPostAnalyticsResponse, common.ErrorWithAttachment)
GetSocialAnalytics(ctx context.Context, in *GetSocialAnalyticsRequest, opts ...grpc_go.CallOption) (*GetSocialAnalyticsResponse, common.ErrorWithAttachment) GetSocialAnalytics(ctx context.Context, in *GetSocialAnalyticsRequest, opts ...grpc_go.CallOption) (*GetSocialAnalyticsResponse, common.ErrorWithAttachment)
// Hashtags 相关 api
AutoHashtags(ctx context.Context, in *AutoHashtagsRequest, opts ...grpc_go.CallOption) (*AutoHashtagsResponse, common.ErrorWithAttachment)
CheckBannedHashtag(ctx context.Context, in *CheckBannedHashtagRequest, opts ...grpc_go.CallOption) (*CheckBannedHashtagResponse, common.ErrorWithAttachment)
RecommendHashtags(ctx context.Context, in *RecommendHashtagsRequest, opts ...grpc_go.CallOption) (*RecommendHashtagsResponse, common.ErrorWithAttachment)
SearchHashtags(ctx context.Context, in *SearchHashtagsRequest, opts ...grpc_go.CallOption) (*SearchHashtagsResponse, common.ErrorWithAttachment)
} }
type ayrshareClient struct { type ayrshareClient struct {
@ -78,6 +83,10 @@ type AyrshareClientImpl struct {
GetPostAnalytics func(ctx context.Context, in *GetPostAnalyticsRequest) (*GetPostAnalyticsResponse, error) GetPostAnalytics func(ctx context.Context, in *GetPostAnalyticsRequest) (*GetPostAnalyticsResponse, error)
GetPostAnalyticsBySocialID func(ctx context.Context, in *GetPostAnalyticsBySocialIDRequest) (*GetPostAnalyticsResponse, error) GetPostAnalyticsBySocialID func(ctx context.Context, in *GetPostAnalyticsBySocialIDRequest) (*GetPostAnalyticsResponse, error)
GetSocialAnalytics func(ctx context.Context, in *GetSocialAnalyticsRequest) (*GetSocialAnalyticsResponse, error) GetSocialAnalytics func(ctx context.Context, in *GetSocialAnalyticsRequest) (*GetSocialAnalyticsResponse, error)
AutoHashtags func(ctx context.Context, in *AutoHashtagsRequest) (*AutoHashtagsResponse, error)
CheckBannedHashtag func(ctx context.Context, in *CheckBannedHashtagRequest) (*CheckBannedHashtagResponse, error)
RecommendHashtags func(ctx context.Context, in *RecommendHashtagsRequest) (*RecommendHashtagsResponse, error)
SearchHashtags func(ctx context.Context, in *SearchHashtagsRequest) (*SearchHashtagsResponse, error)
} }
func (c *AyrshareClientImpl) GetDubboStub(cc *triple.TripleConn) AyrshareClient { func (c *AyrshareClientImpl) GetDubboStub(cc *triple.TripleConn) AyrshareClient {
@ -200,6 +209,30 @@ func (c *ayrshareClient) GetSocialAnalytics(ctx context.Context, in *GetSocialAn
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/GetSocialAnalytics", in, out) return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/GetSocialAnalytics", in, out)
} }
func (c *ayrshareClient) AutoHashtags(ctx context.Context, in *AutoHashtagsRequest, opts ...grpc_go.CallOption) (*AutoHashtagsResponse, common.ErrorWithAttachment) {
out := new(AutoHashtagsResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/AutoHashtags", in, out)
}
func (c *ayrshareClient) CheckBannedHashtag(ctx context.Context, in *CheckBannedHashtagRequest, opts ...grpc_go.CallOption) (*CheckBannedHashtagResponse, common.ErrorWithAttachment) {
out := new(CheckBannedHashtagResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/CheckBannedHashtag", in, out)
}
func (c *ayrshareClient) RecommendHashtags(ctx context.Context, in *RecommendHashtagsRequest, opts ...grpc_go.CallOption) (*RecommendHashtagsResponse, common.ErrorWithAttachment) {
out := new(RecommendHashtagsResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/RecommendHashtags", in, out)
}
func (c *ayrshareClient) SearchHashtags(ctx context.Context, in *SearchHashtagsRequest, opts ...grpc_go.CallOption) (*SearchHashtagsResponse, common.ErrorWithAttachment) {
out := new(SearchHashtagsResponse)
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/SearchHashtags", in, out)
}
// AyrshareServer is the server API for Ayrshare service. // AyrshareServer is the server API for Ayrshare service.
// All implementations must embed UnimplementedAyrshareServer // All implementations must embed UnimplementedAyrshareServer
// for forward compatibility // for forward compatibility
@ -229,6 +262,11 @@ type AyrshareServer interface {
GetPostAnalytics(context.Context, *GetPostAnalyticsRequest) (*GetPostAnalyticsResponse, error) GetPostAnalytics(context.Context, *GetPostAnalyticsRequest) (*GetPostAnalyticsResponse, error)
GetPostAnalyticsBySocialID(context.Context, *GetPostAnalyticsBySocialIDRequest) (*GetPostAnalyticsResponse, error) GetPostAnalyticsBySocialID(context.Context, *GetPostAnalyticsBySocialIDRequest) (*GetPostAnalyticsResponse, error)
GetSocialAnalytics(context.Context, *GetSocialAnalyticsRequest) (*GetSocialAnalyticsResponse, error) GetSocialAnalytics(context.Context, *GetSocialAnalyticsRequest) (*GetSocialAnalyticsResponse, error)
// Hashtags 相关 api
AutoHashtags(context.Context, *AutoHashtagsRequest) (*AutoHashtagsResponse, error)
CheckBannedHashtag(context.Context, *CheckBannedHashtagRequest) (*CheckBannedHashtagResponse, error)
RecommendHashtags(context.Context, *RecommendHashtagsRequest) (*RecommendHashtagsResponse, error)
SearchHashtags(context.Context, *SearchHashtagsRequest) (*SearchHashtagsResponse, error)
mustEmbedUnimplementedAyrshareServer() mustEmbedUnimplementedAyrshareServer()
} }
@ -291,6 +329,18 @@ func (UnimplementedAyrshareServer) GetPostAnalyticsBySocialID(context.Context, *
func (UnimplementedAyrshareServer) GetSocialAnalytics(context.Context, *GetSocialAnalyticsRequest) (*GetSocialAnalyticsResponse, error) { func (UnimplementedAyrshareServer) GetSocialAnalytics(context.Context, *GetSocialAnalyticsRequest) (*GetSocialAnalyticsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetSocialAnalytics not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetSocialAnalytics not implemented")
} }
func (UnimplementedAyrshareServer) AutoHashtags(context.Context, *AutoHashtagsRequest) (*AutoHashtagsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AutoHashtags not implemented")
}
func (UnimplementedAyrshareServer) CheckBannedHashtag(context.Context, *CheckBannedHashtagRequest) (*CheckBannedHashtagResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CheckBannedHashtag not implemented")
}
func (UnimplementedAyrshareServer) RecommendHashtags(context.Context, *RecommendHashtagsRequest) (*RecommendHashtagsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RecommendHashtags not implemented")
}
func (UnimplementedAyrshareServer) SearchHashtags(context.Context, *SearchHashtagsRequest) (*SearchHashtagsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SearchHashtags not implemented")
}
func (s *UnimplementedAyrshareServer) XXX_SetProxyImpl(impl protocol.Invoker) { func (s *UnimplementedAyrshareServer) XXX_SetProxyImpl(impl protocol.Invoker) {
s.proxyImpl = impl s.proxyImpl = impl
} }
@ -841,6 +891,122 @@ func _Ayrshare_GetSocialAnalytics_Handler(srv interface{}, ctx context.Context,
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _Ayrshare_AutoHashtags_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(AutoHashtagsRequest)
if err := dec(in); err != nil {
return nil, err
}
base := srv.(dubbo3.Dubbo3GrpcService)
args := []interface{}{}
args = append(args, in)
md, _ := metadata.FromIncomingContext(ctx)
invAttachment := make(map[string]interface{}, len(md))
for k, v := range md {
invAttachment[k] = v
}
invo := invocation.NewRPCInvocation("AutoHashtags", args, invAttachment)
if interceptor == nil {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
info := &grpc_go.UnaryServerInfo{
Server: srv,
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
return interceptor(ctx, in, info, handler)
}
func _Ayrshare_CheckBannedHashtag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(CheckBannedHashtagRequest)
if err := dec(in); err != nil {
return nil, err
}
base := srv.(dubbo3.Dubbo3GrpcService)
args := []interface{}{}
args = append(args, in)
md, _ := metadata.FromIncomingContext(ctx)
invAttachment := make(map[string]interface{}, len(md))
for k, v := range md {
invAttachment[k] = v
}
invo := invocation.NewRPCInvocation("CheckBannedHashtag", args, invAttachment)
if interceptor == nil {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
info := &grpc_go.UnaryServerInfo{
Server: srv,
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
return interceptor(ctx, in, info, handler)
}
func _Ayrshare_RecommendHashtags_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(RecommendHashtagsRequest)
if err := dec(in); err != nil {
return nil, err
}
base := srv.(dubbo3.Dubbo3GrpcService)
args := []interface{}{}
args = append(args, in)
md, _ := metadata.FromIncomingContext(ctx)
invAttachment := make(map[string]interface{}, len(md))
for k, v := range md {
invAttachment[k] = v
}
invo := invocation.NewRPCInvocation("RecommendHashtags", args, invAttachment)
if interceptor == nil {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
info := &grpc_go.UnaryServerInfo{
Server: srv,
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
return interceptor(ctx, in, info, handler)
}
func _Ayrshare_SearchHashtags_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
in := new(SearchHashtagsRequest)
if err := dec(in); err != nil {
return nil, err
}
base := srv.(dubbo3.Dubbo3GrpcService)
args := []interface{}{}
args = append(args, in)
md, _ := metadata.FromIncomingContext(ctx)
invAttachment := make(map[string]interface{}, len(md))
for k, v := range md {
invAttachment[k] = v
}
invo := invocation.NewRPCInvocation("SearchHashtags", args, invAttachment)
if interceptor == nil {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
info := &grpc_go.UnaryServerInfo{
Server: srv,
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
return result, result.Error()
}
return interceptor(ctx, in, info, handler)
}
// Ayrshare_ServiceDesc is the grpc_go.ServiceDesc for Ayrshare service. // Ayrshare_ServiceDesc is the grpc_go.ServiceDesc for Ayrshare service.
// It's only intended for direct use with grpc_go.RegisterService, // It's only intended for direct use with grpc_go.RegisterService,
// and not to be introspected or modified (even as a copy) // and not to be introspected or modified (even as a copy)
@ -920,6 +1086,22 @@ var Ayrshare_ServiceDesc = grpc_go.ServiceDesc{
MethodName: "GetSocialAnalytics", MethodName: "GetSocialAnalytics",
Handler: _Ayrshare_GetSocialAnalytics_Handler, Handler: _Ayrshare_GetSocialAnalytics_Handler,
}, },
{
MethodName: "AutoHashtags",
Handler: _Ayrshare_AutoHashtags_Handler,
},
{
MethodName: "CheckBannedHashtag",
Handler: _Ayrshare_CheckBannedHashtag_Handler,
},
{
MethodName: "RecommendHashtags",
Handler: _Ayrshare_RecommendHashtags_Handler,
},
{
MethodName: "SearchHashtags",
Handler: _Ayrshare_SearchHashtags_Handler,
},
}, },
Streams: []grpc_go.StreamDesc{}, Streams: []grpc_go.StreamDesc{},
Metadata: "pb/ayrshare.proto", Metadata: "pb/ayrshare.proto",

View File

@ -38,6 +38,12 @@ service Ayrshare {
rpc GetPostAnalytics(GetPostAnalyticsRequest) returns (GetPostAnalyticsResponse); rpc GetPostAnalytics(GetPostAnalyticsRequest) returns (GetPostAnalyticsResponse);
rpc GetPostAnalyticsBySocialID(GetPostAnalyticsBySocialIDRequest) returns (GetPostAnalyticsResponse); rpc GetPostAnalyticsBySocialID(GetPostAnalyticsBySocialIDRequest) returns (GetPostAnalyticsResponse);
rpc GetSocialAnalytics(GetSocialAnalyticsRequest) returns (GetSocialAnalyticsResponse); rpc GetSocialAnalytics(GetSocialAnalyticsRequest) returns (GetSocialAnalyticsResponse);
// Hashtags api
rpc AutoHashtags(AutoHashtagsRequest) returns (AutoHashtagsResponse);
rpc CheckBannedHashtag(CheckBannedHashtagRequest) returns (CheckBannedHashtagResponse);
rpc RecommendHashtags(RecommendHashtagsRequest) returns (RecommendHashtagsResponse);
rpc SearchHashtags(SearchHashtagsRequest) returns (SearchHashtagsResponse);
} }
// Instagram // Instagram
@ -1106,3 +1112,110 @@ message GetSocialAnalyticsResponse {
string twitter = 12 [json_name = "twitter"]; string twitter = 12 [json_name = "twitter"];
string youtube = 13 [json_name = "youtube"]; string youtube = 13 [json_name = "youtube"];
} }
// ========== Hashtags ==========
// AutoHashtagsRequest
message AutoHashtagsRequest {
string post = 1 [json_name = "post", (validator.field) = {string_not_empty: true, human_error: "post内容不能为空"}];
int32 max = 2 [json_name = "max"];
string position = 3 [json_name = "position"];
string language = 4 [json_name = "language"];
string profileKey = 5 [json_name = "profileKey"];
}
// AutoHashtagsResponse
message AutoHashtagsResponse {
string post = 1 [json_name = "post"];
string action = 2 [json_name = "action"];
string status = 3 [json_name = "status"];
int32 code = 4 [json_name = "code"];
string message = 5 [json_name = "message"];
}
// CheckBannedHashtagRequest
message CheckBannedHashtagRequest {
string hashtag = 1 [json_name = "hashtag", (validator.field) = {string_not_empty: true, human_error: "hashtag不能为空"}];
string profileKey = 2 [json_name = "profileKey"];
}
// CheckBannedHashtagResponse
message CheckBannedHashtagResponse {
string hashtag = 1 [json_name = "hashtag"];
bool banned = 2 [json_name = "banned"];
string action = 3 [json_name = "action"];
string status = 4 [json_name = "status"];
int32 code = 5 [json_name = "code"];
string message = 6 [json_name = "message"];
}
// HashtagRecommendation
message HashtagRecommendation {
int64 viewCount = 1 [json_name = "viewCount"];
string name = 2 [json_name = "name"];
}
// RecommendHashtagsRequest
message RecommendHashtagsRequest {
string keyword = 1 [json_name = "keyword", (validator.field) = {string_not_empty: true, human_error: "keyword不能为空"}];
string profileKey = 2 [json_name = "profileKey"];
}
// RecommendHashtagsResponse
message RecommendHashtagsResponse {
string keyword = 1 [json_name = "keyword"];
repeated HashtagRecommendation recommendations = 2 [json_name = "recommendations"];
string action = 3 [json_name = "action"];
string status = 4 [json_name = "status"];
int32 code = 5 [json_name = "code"];
string message = 6 [json_name = "message"];
}
// SearchHashtagsRequest
message SearchHashtagsRequest {
string keyword = 1 [json_name = "keyword", (validator.field) = {string_not_empty: true, human_error: "keyword不能为空"}];
string searchType = 2 [json_name = "searchType"];
string profileKey = 3 [json_name = "profileKey"];
}
// SearchHashtagInfo
message SearchHashtagInfo {
string id = 1 [json_name = "id"];
string name = 2 [json_name = "name"];
}
// SearchHashtagChild children.data
message SearchHashtagChild {
string id = 1 [json_name = "id"];
}
// SearchHashtagChildren children
message SearchHashtagChildren {
repeated SearchHashtagChild data = 1 [json_name = "data"];
}
// SearchHashtagMedia Instagram
message SearchHashtagMedia {
string caption = 1 [json_name = "caption"];
SearchHashtagChildren children = 2 [json_name = "children"];
int32 commentsCount = 3 [json_name = "commentsCount"];
string id = 4 [json_name = "id"];
int32 likeCount = 5 [json_name = "likeCount"];
string mediaType = 6 [json_name = "mediaType"];
string mediaUrl = 7 [json_name = "mediaUrl"];
string permalink = 8 [json_name = "permalink"];
string timestamp = 9 [json_name = "timestamp"];
}
// SearchHashtagsResponse
message SearchHashtagsResponse {
string status = 1 [json_name = "status"];
SearchHashtagInfo hashtag = 2 [json_name = "hashtag"];
repeated SearchHashtagMedia searchResults = 3 [json_name = "searchResults"];
int32 count = 4 [json_name = "count"];
string lastUpdated = 5 [json_name = "lastUpdated"];
string nextUpdate = 6 [json_name = "nextUpdate"];
string action = 7 [json_name = "action"];
int32 code = 8 [json_name = "code"];
string message = 9 [json_name = "message"];
}

12
pkg/msg/tag_msg.go Normal file
View File

@ -0,0 +1,12 @@
package msg
const (
// Hashtags 相关错误消息
ErrorAutoHashtagsFailed = "自动生成标签失败"
ErrorCheckBannedHashtagsFailed = "查看被禁用的标签失败"
ErrorRecommendHashtagsFailed = "推荐话题标签失败"
ErrorSearchHashtagsFailed = "搜索话题标签失败"
ErrHashtagEmpty = "hashtag不能为空"
ErrKeywordEmpty = "keyword不能为空"
)