Skip to content

Commit

Permalink
fix recommendations when session is empty
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobobryant committed Aug 24, 2017
1 parent bb983b4 commit 56c72b2
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 89 deletions.
95 changes: 10 additions & 85 deletions reco/src/reco/reco.clj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
[set_state [java.util.Map] void]
[get_last_event_id [] long]
[set_last_event_id [long] void]
[session_size [] int]
^:static [modelify [java.util.Collection long] java.util.Map]
^:static [modelify [java.util.Collection long java.util.Collection String] java.util.Map]
^:static [parse_top_tracks [String] java.util.List]
Expand Down Expand Up @@ -50,14 +51,6 @@
content-ratio content-n content-score])

(defrecord Song [artist album title source spotify_id duration])
;danceability
;energy
;mode
;speechiness
;acousticness
;instrumentalness
;liveness
;valence])

(defn dbg [desc arg]
(when debug
Expand Down Expand Up @@ -140,49 +133,11 @@
nil
(* sim (if skipped -1 1)))))

;(defn dot-product [vectors]
; (reduce + (apply map * vectors)))
;
;(defn norm [v]
; (Math/sqrt (reduce + (map #(* % %) v))))
;
;(defn cosine [vectors]
; (/ (dot-product vectors)
; (apply * (map norm vectors))))
;
;(defn feature-sim [library a b skipped]
; (let [features [:danceability
; :energy
; :mode
; :speechiness
; :acousticness
; :instrumentalness
; :liveness
; :valence]
; vectors (map (fn [song-id]
; (map (fn [feature] (get-in library [song-id feature]))
; features))
; [a b])
; distance (cosine vectors)
; sim (- (* distance 2) 1)]
; ;(println "feature distance between" (get-in library [a :title]) "and"
; ; (get-in library [b :title]) "is" distance)
; (if (and skipped (< sim 0))
; nil
; (* sim (if skipped -1 1)))))

(defn update-cand [[cand-id data] library model skipped]
[cand-id
(let [sim (sim-score model cand-id skipped)
cand-artist (get-in library [cand-id :artist])
content-sim (sim-score model cand-artist skipped)]
;(if (every? some? (map #(get-in library [% :mode])
; [cand-id other-id]))
; (feature-sim library cand-id other-id skipped)
; (let [s (sim-score model other-artist cand-artist skipped)]
; (if s
; (min s (if (= other-artist cand-artist) 1 0.8))
; nil)))]
(cond-> data
sim (update-score :collaborative sim)
content-sim (update-score :content content-sim)))])
Expand Down Expand Up @@ -233,25 +188,14 @@
:content-score 1)])
candidates)))

;(defn update-model [model session library]
; (let [partial-model (mk-model session library)]
; (merge-with (fn [{score-a :score n-a :n} {score-b :score n-b :n}]
; (Cell. (/ (+ (* score-a n-a) (* score-b n-b))
; (+ n-a n-b))
; (+ n-a n-b)))
; model partial-model)))



(defn add-event [state model song-id skipped timestamp do-cand-update]
(dbg "add-event song-id" song-id)
(let [time-delta (- timestamp (:last-time state))
new-session (> time-delta ses-threshold)
; song id -1 represents the empty session. It gives the model
; something to work with when a session is just getting
; started.
session (if new-session
{-1 false song-id skipped}
{song-id skipped}
(assoc (:session state) song-id skipped))]

(when (< timestamp (:last-time state))
Expand All @@ -260,13 +204,12 @@

(cond-> state
true (assoc :last-time timestamp :session session)
true (update-in [:candidates song-id :event-vec]
#(conj % (Event. (/ timestamp 86400) skipped)))
;true (update-in [:candidates song-id :event-vec]
; #(conj % (Event. (/ timestamp 86400) skipped)))
new-session (update :candidates reset-candidates)
new-session (update-candidates (walk/keywordize-keys model)
-1 false)
do-cand-update (update-candidates (walk/keywordize-keys model)
song-id skipped)
;(and new-session do-cand-update) (update-candidates (walk/keywordize-keys model)
; -1 false)
do-cand-update (update-candidates (walk/keywordize-keys model) skipped)
true (assoc :new-model (if new-session
(walk/stringify-keys
(mk-model (:session state)
Expand All @@ -284,25 +227,6 @@
([this model song-id skipped]
(.add_event this model song-id skipped (now))))

;(defn init-model [this]
; (println "init model")
; (swap! (.state this)
; (fn [state]
; (let [[old-sessions cur-session]
; (if (> ses-threshold (- (now) (:last-time state)))
; [(rest (:sessions state)) (first (:sessions state))]
; [(:sessions state) nil])
; new-candidates
; (loop [cands (reset-candidates (:candidates state))
; session cur-session]
; (if (empty? session)
; cands
; (let [[song-id skipped] (first session)]
; (recur (update-candidates cands (:library state) new-model
; song-id skipped)
; (rest session)))))]
; (assoc state :model new-model :candidates new-candidates)))))

(defn calc-confidence [n]
(- 1 (/ 1 (Math/pow 1.5 n))))
(def calc-confidence (memoize calc-confidence))
Expand Down Expand Up @@ -347,8 +271,6 @@
(assoc (library song-id) :_id song-id)))))

(defn -pick_next [this local-only]
;(when (not (:model @@this))
; (init-model this))
(pick @@this local-only pick-with-algorithm))

(defn -pick_random [this local-only]
Expand Down Expand Up @@ -388,6 +310,9 @@
score])
artist-model)))))

(defn -session_size [this]
(count (:session @@this)))

(defn -parse_top_tracks [response]
(let [data (json/read-str response)]
(map (fn [item] {"spotify_id" (get item "uri")
Expand Down
15 changes: 11 additions & 4 deletions src/com/jacobobryant/moody/Moody.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,13 @@ private void init(InitProgressListener listener) {
rec = new reco(cursor_to_maps(
db.rawQuery("SELECT _id, artist, album, title, source, " +
"spotify_id, duration FROM songs", null)));


SharedPreferences settings = PlaybackService.getSettings(context);
long last_event_in_model = -1; //settings.getLong(PrefKeys.LAST_EVENT_IN_MODEL, -1);
db.execSQL("DELETE FROM model"); // lololol
db.execSQL("DELETE FROM artist_model");
long last_event_in_model = settings.getLong(PrefKeys.LAST_EVENT_IN_MODEL, -1);
Log.d(C.TAG, "last_event_in_model: " + last_event_in_model);
//long last_event_in_model = -1;
//db.execSQL("DELETE FROM model"); // lololol
//db.execSQL("DELETE FROM artist_model");

result = db.rawQuery("SELECT song_id, skipped, time, events._id, artist " +
"FROM events JOIN songs on song_id = songs._id WHERE events._id > ? ORDER BY time ASC",
Expand Down Expand Up @@ -234,6 +234,13 @@ private void add_event(long song_id, Long event_id, boolean skipped, Long second
db.setTransactionSuccessful();
db.endTransaction();
}
if (rec.session_size() == 1) {
if (seconds == null) {
rec.add_event(get_model(db, -1, null), -1, false);
} else {
rec.add_event(get_model(db, -1, null), -1, false, seconds, do_update);
}
}
db.close();
}

Expand Down

0 comments on commit 56c72b2

Please sign in to comment.