2026-06-25 08:20:03 +00:00
|
|
|
|
package viral
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"encoding/json"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
func firstJSONString(obj map[string]json.RawMessage, keys ...string) string {
|
|
|
|
|
|
for _, key := range keys {
|
|
|
|
|
|
raw, ok := obj[key]
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
var value string
|
|
|
|
|
|
if err := json.Unmarshal(raw, &value); err == nil {
|
|
|
|
|
|
if trimmed := strings.TrimSpace(value); trimmed != "" {
|
|
|
|
|
|
return trimmed
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func flexibleStringFromItem(raw json.RawMessage) string {
|
|
|
|
|
|
if len(raw) == 0 {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
var value string
|
|
|
|
|
|
if err := json.Unmarshal(raw, &value); err == nil {
|
|
|
|
|
|
return strings.TrimSpace(value)
|
|
|
|
|
|
}
|
|
|
|
|
|
var obj map[string]json.RawMessage
|
|
|
|
|
|
if err := json.Unmarshal(raw, &obj); err != nil {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
if line := firstJSONString(obj, "title", "name", "label", "pillar", "tag", "text", "summary", "description", "value", "content"); line != "" {
|
|
|
|
|
|
return line
|
|
|
|
|
|
}
|
|
|
|
|
|
parts := []string{}
|
|
|
|
|
|
for _, key := range []string{"title", "name", "label"} {
|
|
|
|
|
|
if part := firstJSONString(obj, key); part != "" {
|
|
|
|
|
|
parts = append(parts, part)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if detail := firstJSONString(obj, "description", "summary", "detail", "reason"); detail != "" {
|
|
|
|
|
|
parts = append(parts, detail)
|
|
|
|
|
|
}
|
|
|
|
|
|
return strings.TrimSpace(strings.Join(parts, ":"))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func parseFlexibleStringList(raw json.RawMessage) []string {
|
|
|
|
|
|
if len(raw) == 0 || string(raw) == "null" {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
var items []string
|
|
|
|
|
|
if err := json.Unmarshal(raw, &items); err == nil {
|
|
|
|
|
|
return cleanLines(items)
|
|
|
|
|
|
}
|
|
|
|
|
|
var single string
|
|
|
|
|
|
if err := json.Unmarshal(raw, &single); err == nil && strings.TrimSpace(single) != "" {
|
|
|
|
|
|
return cleanLines([]string{single})
|
|
|
|
|
|
}
|
|
|
|
|
|
var arr []json.RawMessage
|
|
|
|
|
|
if err := json.Unmarshal(raw, &arr); err != nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
out := make([]string, 0, len(arr))
|
|
|
|
|
|
for _, item := range arr {
|
|
|
|
|
|
if line := flexibleStringFromItem(item); line != "" {
|
|
|
|
|
|
out = append(out, line)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return cleanLines(out)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func parseFlexibleSuggestedTags(raw json.RawMessage) []SuggestedTag {
|
|
|
|
|
|
if len(raw) == 0 || string(raw) == "null" {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
var tags []SuggestedTag
|
|
|
|
|
|
if err := json.Unmarshal(raw, &tags); err == nil && len(tags) > 0 {
|
|
|
|
|
|
return cleanSuggestedTags(tags)
|
|
|
|
|
|
}
|
|
|
|
|
|
var strs []string
|
|
|
|
|
|
if err := json.Unmarshal(raw, &strs); err == nil {
|
|
|
|
|
|
out := make([]SuggestedTag, 0, len(strs))
|
|
|
|
|
|
for _, item := range strs {
|
|
|
|
|
|
item = strings.TrimSpace(item)
|
|
|
|
|
|
if item != "" {
|
|
|
|
|
|
out = append(out, SuggestedTag{Tag: item})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return cleanSuggestedTags(out)
|
|
|
|
|
|
}
|
|
|
|
|
|
var arr []json.RawMessage
|
|
|
|
|
|
if err := json.Unmarshal(raw, &arr); err != nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
out := make([]SuggestedTag, 0, len(arr))
|
|
|
|
|
|
for _, item := range arr {
|
|
|
|
|
|
if tag := decodeSuggestedTagItem(item); tag.Tag != "" {
|
|
|
|
|
|
out = append(out, tag)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return cleanSuggestedTags(out)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func decodeSuggestedTagItem(raw json.RawMessage) SuggestedTag {
|
|
|
|
|
|
var tag SuggestedTag
|
|
|
|
|
|
if err := json.Unmarshal(raw, &tag); err == nil && strings.TrimSpace(tag.Tag) != "" {
|
|
|
|
|
|
return tag
|
|
|
|
|
|
}
|
|
|
|
|
|
var snake struct {
|
|
|
|
|
|
Tag string `json:"tag"`
|
|
|
|
|
|
Reason string `json:"reason"`
|
|
|
|
|
|
SearchIntent string `json:"search_intent"`
|
|
|
|
|
|
SearchType string `json:"search_type"`
|
|
|
|
|
|
}
|
|
|
|
|
|
if err := json.Unmarshal(raw, &snake); err == nil && strings.TrimSpace(snake.Tag) != "" {
|
|
|
|
|
|
return SuggestedTag{
|
|
|
|
|
|
Tag: strings.TrimSpace(snake.Tag),
|
|
|
|
|
|
Reason: strings.TrimSpace(snake.Reason),
|
|
|
|
|
|
SearchIntent: strings.TrimSpace(snake.SearchIntent),
|
|
|
|
|
|
SearchType: strings.TrimSpace(snake.SearchType),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if line := flexibleStringFromItem(raw); line != "" {
|
|
|
|
|
|
return SuggestedTag{Tag: line}
|
|
|
|
|
|
}
|
|
|
|
|
|
return SuggestedTag{}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func pickRawMessage(root map[string]json.RawMessage, keys ...string) json.RawMessage {
|
|
|
|
|
|
for _, key := range keys {
|
|
|
|
|
|
if raw, ok := root[key]; ok && len(raw) > 0 && string(raw) != "null" {
|
|
|
|
|
|
return raw
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
2026-06-25 09:34:28 +00:00
|
|
|
|
}
|