tagger.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. package processor
  2. import (
  3. "strings"
  4. )
  5. // Industry keywords for matching. Extensible via config in the future.
  6. var industryKeywords = map[string][]string{
  7. "机场": {
  8. "机场", "节点", "订阅", "clash", "v2ray", "trojan", "shadowsocks", "ss/ssr",
  9. "翻墙", "梯子", "科学上网", "加速器", "proxy", "代理",
  10. },
  11. "VPN": {
  12. "vpn", "VPN", "wireguard", "openvpn",
  13. },
  14. }
  15. // TagAndGrade assigns industry_tag and level (Hot/Warm/Cold) to each merchant.
  16. func TagAndGrade(merchants []MergedMerchant) []TaggedMerchant {
  17. var result []TaggedMerchant
  18. for _, m := range merchants {
  19. tagged := TaggedMerchant{Merged: m}
  20. // Industry matching: check merchant_name + original_text
  21. text := strings.ToLower(m.Best.MerchantName + " " + m.Best.OriginalText)
  22. for industry, keywords := range industryKeywords {
  23. for _, kw := range keywords {
  24. if strings.Contains(text, strings.ToLower(kw)) {
  25. tagged.IndustryTag = industry
  26. break
  27. }
  28. }
  29. if tagged.IndustryTag != "" {
  30. break
  31. }
  32. }
  33. // Inherit from raw if no match found
  34. if tagged.IndustryTag == "" && m.Best.IndustryTag != "" {
  35. tagged.IndustryTag = m.Best.IndustryTag
  36. }
  37. // Level grading
  38. hasIndustry := tagged.IndustryTag != ""
  39. hasWebsiteOrEmail := m.Best.Website != "" || m.Best.Email != ""
  40. switch {
  41. case hasIndustry && hasWebsiteOrEmail:
  42. tagged.Level = "Hot"
  43. case hasIndustry:
  44. tagged.Level = "Warm"
  45. default:
  46. tagged.Level = "Cold"
  47. }
  48. result = append(result, tagged)
  49. }
  50. return result
  51. }
  52. // TaggedMerchant is the final output of the processor.
  53. type TaggedMerchant struct {
  54. Merged MergedMerchant
  55. IndustryTag string
  56. Level string // Hot / Warm / Cold
  57. }