0.3.06
This commit is contained in:
@@ -109,6 +109,11 @@ type Profile struct {
|
||||
// good reason to *tell* someone about a title and a poor reason to rank by it: two
|
||||
// films sharing an actor are often nothing alike.
|
||||
PersonWeights map[string]float64
|
||||
// DecadeWeights and ReasonEvidence retain just enough of the source history for the
|
||||
// explanation layer to say why a particular title fits. They do not participate in
|
||||
// ranking: ordering and wording remain deliberately separate concerns.
|
||||
DecadeWeights map[int]float64
|
||||
ReasonEvidence []ReasonEvidence
|
||||
// Seen holds item ids *and* series ids already watched or in progress, so a
|
||||
// recommendation never suggests something the user is already partway through.
|
||||
Seen map[string]bool
|
||||
@@ -116,6 +121,11 @@ type Profile struct {
|
||||
Seeds []Seed
|
||||
}
|
||||
|
||||
type ReasonEvidence struct {
|
||||
Item Item
|
||||
Favourite bool
|
||||
}
|
||||
|
||||
func (p Profile) IsEmpty() bool { return len(p.GenreWeights) == 0 && len(p.Seeds) == 0 }
|
||||
|
||||
// Decode parses raw Emby items, keeping the original payload attached.
|
||||
@@ -141,14 +151,26 @@ func BuildProfile(history, favorites []Item) Profile {
|
||||
GenreWeights: map[string]float64{},
|
||||
StudioWeights: map[string]float64{},
|
||||
PersonWeights: map[string]float64{},
|
||||
DecadeWeights: map[int]float64{},
|
||||
Seen: map[string]bool{},
|
||||
SeenTitles: map[string]bool{},
|
||||
}
|
||||
|
||||
seedSeen := map[string]bool{}
|
||||
tasteSeen := map[string]bool{}
|
||||
reasonSeen := map[string]bool{}
|
||||
for i, item := range history {
|
||||
profile.markSeen(item)
|
||||
reasonItem := item
|
||||
reasonItem.Raw = nil
|
||||
reasonID := item.ID
|
||||
if item.SeriesID != "" {
|
||||
reasonID = item.SeriesID
|
||||
}
|
||||
if reasonID != "" && !reasonSeen[reasonID] {
|
||||
reasonSeen[reasonID] = true
|
||||
profile.ReasonEvidence = append(profile.ReasonEvidence, ReasonEvidence{Item: reasonItem})
|
||||
}
|
||||
|
||||
// Several episodes of one series are evidence for one taste, not several
|
||||
// independent tastes. Keep the newest occurrence's recency weight and still
|
||||
@@ -176,6 +198,15 @@ func BuildProfile(history, favorites []Item) Profile {
|
||||
|
||||
for _, item := range favorites {
|
||||
profile.absorb(item, favoriteWeight)
|
||||
reasonItem := item
|
||||
reasonItem.Raw = nil
|
||||
reasonID := item.ID
|
||||
if reasonID != "" && !reasonSeen[reasonID] {
|
||||
reasonSeen[reasonID] = true
|
||||
profile.ReasonEvidence = append(profile.ReasonEvidence, ReasonEvidence{
|
||||
Item: reasonItem, Favourite: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
return profile
|
||||
}
|
||||
@@ -223,6 +254,12 @@ func (p *Profile) absorbTaste(item Item, weight float64) {
|
||||
p.PersonWeights[name] += weight
|
||||
}
|
||||
}
|
||||
if item.ProductionYear > 0 {
|
||||
if p.DecadeWeights == nil {
|
||||
p.DecadeWeights = map[int]float64{}
|
||||
}
|
||||
p.DecadeWeights[item.ProductionYear/10*10] += weight
|
||||
}
|
||||
}
|
||||
|
||||
// isExplainablePerson keeps the cast list down to the roles a viewer would recognise as
|
||||
|
||||
Reference in New Issue
Block a user