thread-master/apps/backend/internal/module/radar/domain/suggest.go

97 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package domain
import "strings"
const (
SuggestUsageInclude = "include"
SuggestUsageExclude = "exclude"
SuggestBasisAudience = "audience"
SuggestBasisPain = "pain"
SuggestBasisContext = "context"
SuggestBasisTag = "tag"
SuggestBasisCapability = "capability"
SuggestBasisExclude = "exclude"
// 建議數量上限:清單要能一眼看完並逐條決定,不是丟一大串讓人放棄。
MaxSuggestions = 20
DefaultSuggestions = 8
)
func IsSuggestionBasisKind(kind string) bool {
switch strings.ToLower(strings.TrimSpace(kind)) {
case SuggestBasisAudience, SuggestBasisPain, SuggestBasisContext, SuggestBasisTag, SuggestBasisCapability, SuggestBasisExclude:
return true
default:
return false
}
}
/*
WatchTermSuggestion 是一則關鍵字建議。
Reason 是必填的:使用者要逐條決定採不採用,看不到「為什麼建議這個詞」就只能全採或全不採,
那這個功能就退化成一個猜測產生器。
*/
type WatchTermSuggestion struct {
Term string `json:"term"`
Reason string `json:"reason"`
Usage string `json:"usage"`
BasisKind string `json:"basis_kind,omitempty"`
BasisText string `json:"basis_text,omitempty"`
}
func NormalizeSuggestUsage(s string) string {
if strings.EqualFold(strings.TrimSpace(s), SuggestUsageExclude) {
return SuggestUsageExclude
}
return SuggestUsageInclude
}
/*
CleanSuggestions 收掉空白與重複,丟掉沒有理由的項目,並套用數量上限。
沒有理由的項目直接丟補一句「AI 建議」等於假裝有理由,比少一則更糟。
include 關鍵字必須通過 Threads 短詞規則IsThreadsSearchable不合規整條丟掉、不截短
避免產出半截怪詞。exclude 仍用較寬的長度界線(訂閱排除詞可能較長)。
*/
func CleanSuggestions(in []WatchTermSuggestion, limit int) []WatchTermSuggestion {
if limit <= 0 || limit > MaxSuggestions {
limit = MaxSuggestions
}
out := make([]WatchTermSuggestion, 0, len(in))
seen := map[string]bool{}
for _, s := range in {
term := NormalizeSearchTerm(s.Term)
reason := strings.TrimSpace(s.Reason)
if term == "" || reason == "" {
continue
}
usage := NormalizeSuggestUsage(s.Usage)
if usage == SuggestUsageInclude {
if !IsThreadsSearchable(term) {
continue
}
} else {
// exclude: keep broader length; still reject empty after normalize
n := len([]rune(term))
if n < MinTermLen || n > MaxTermLen {
continue
}
}
key := strings.ToLower(term)
if seen[key] {
continue
}
seen[key] = true
out = append(out, WatchTermSuggestion{
Term: term, Reason: reason, Usage: usage,
BasisKind: strings.TrimSpace(s.BasisKind), BasisText: strings.TrimSpace(s.BasisText),
})
if len(out) >= limit {
break
}
}
return out
}