Initial commit
This commit is contained in:
84
internal/scheduler/alert.go
Normal file
84
internal/scheduler/alert.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"veola/internal/apify"
|
||||
)
|
||||
|
||||
// ShouldAlert returns true if the result should trigger an alert.
|
||||
//
|
||||
// - Result must not already be in DB (caller checks that first).
|
||||
// - If targetPrice is nil, alert on every new result.
|
||||
// - If targetPrice is non-nil, alert only when price <= targetPrice.
|
||||
//
|
||||
// price=0 is treated as "unknown" and never alerts under a target.
|
||||
func ShouldAlert(targetPrice *float64, price float64) bool {
|
||||
if targetPrice == nil {
|
||||
return true
|
||||
}
|
||||
if price <= 0 {
|
||||
return false
|
||||
}
|
||||
return price <= *targetPrice
|
||||
}
|
||||
|
||||
// FilterResults applies match-confidence and out-of-stock filtering. Returns
|
||||
// a fresh slice; the input is not mutated.
|
||||
func FilterResults(in []apify.UnifiedResult, minConfidence float64, includeOOS bool) []apify.UnifiedResult {
|
||||
out := make([]apify.UnifiedResult, 0, len(in))
|
||||
for _, r := range in {
|
||||
if !includeOOS && r.OutOfStock {
|
||||
continue
|
||||
}
|
||||
if r.MatchConfidence != 0 && r.MatchConfidence < minConfidence {
|
||||
continue
|
||||
}
|
||||
if r.URL == "" || r.Price <= 0 {
|
||||
continue
|
||||
}
|
||||
out = append(out, r)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ApplyItemFilters drops results below minPrice (when set) and any whose title
|
||||
// contains one of excludeKeywords (case-insensitive substring match). Pass nil
|
||||
// or empty for either to skip that filter. Returns a fresh slice.
|
||||
func ApplyItemFilters(in []apify.UnifiedResult, minPrice *float64, excludeKeywords []string) []apify.UnifiedResult {
|
||||
lowered := make([]string, 0, len(excludeKeywords))
|
||||
for _, k := range excludeKeywords {
|
||||
k = strings.ToLower(strings.TrimSpace(k))
|
||||
if k != "" {
|
||||
lowered = append(lowered, k)
|
||||
}
|
||||
}
|
||||
out := make([]apify.UnifiedResult, 0, len(in))
|
||||
outer:
|
||||
for _, r := range in {
|
||||
if minPrice != nil && r.Price < *minPrice {
|
||||
continue
|
||||
}
|
||||
if len(lowered) > 0 {
|
||||
title := strings.ToLower(r.Title)
|
||||
for _, k := range lowered {
|
||||
if strings.Contains(title, k) {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
}
|
||||
out = append(out, r)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// PickBest returns the index of the lowest-priced result, or -1 if none.
|
||||
func PickBest(rs []apify.UnifiedResult) int {
|
||||
best := -1
|
||||
for i, r := range rs {
|
||||
if best == -1 || r.Price < rs[best].Price {
|
||||
best = i
|
||||
}
|
||||
}
|
||||
return best
|
||||
}
|
||||
Reference in New Issue
Block a user