added comments; some refactoring

master
Abhinav Sarkar 2010-11-04 00:25:54 +05:30
parent 0bb5911351
commit 63635873ca
2 changed files with 50 additions and 20 deletions

View File

@ -4,7 +4,7 @@
[org.apache.http HttpException] [org.apache.http HttpException]
[org.apache.http.auth AuthScope UsernamePasswordCredentials] [org.apache.http.auth AuthScope UsernamePasswordCredentials]
[org.apache.http.client.methods HttpGet] [org.apache.http.client.methods HttpGet]
[org.apache.http.client ResponseHandler HttpClient] [org.apache.http.client HttpClient]
[org.apache.http.impl.client DefaultHttpClient] [org.apache.http.impl.client DefaultHttpClient]
[org.apache.http.params BasicHttpParams HttpParams]) [org.apache.http.params BasicHttpParams HttpParams])
(:use [clojure.java.io :only (reader resource as-file)] (:use [clojure.java.io :only (reader resource as-file)]
@ -18,9 +18,12 @@
(defmethod trace :l [msg _ arg] (do (println msg ":" arg) arg)) (defmethod trace :l [msg _ arg] (do (println msg ":" arg) arg))
(defmethod trace :f [arg _ msg] (do (println msg ":" arg) arg)) (defmethod trace :f [arg _ msg] (do (println msg ":" arg) arg))
;names of adjective files
(def adjective-files ["negative" "neutral" "positive"]) (def adjective-files ["negative" "neutral" "positive"])
(defn adjectives [] (defn adjectives
"Loads the adjective files and returns a map of adjective to its type."
[]
(->> adjective-files (->> adjective-files
(map #(str "clj_twitter_feelings/adjectives/" % ".txt")) (map #(str "clj_twitter_feelings/adjectives/" % ".txt"))
(map resource) (map resource)
@ -29,31 +32,39 @@
(let [adjective-type (let [adjective-type
(-> url .toString (.split "/") last (.split "\\.") first)] (-> url .toString (.split "/") last (.split "\\.") first)]
(reduce (reduce
(fn [acc word] (fn [acc word] (assoc! acc word adjective-type))
(assoc! acc word adjective-type))
acc acc
(read-lines url)))) (read-lines url))))
(transient {})) (transient {}))
(persistent!))) (persistent!)))
(defn safe-divide [n d] (if (zero? d) 0 (float (/ n d)))) (defn safe-divide
"If denominator is 0 returns 0 else returns numerator divided by denominator."
[n d] (if (zero? d) 0 (float (/ n d))))
(def split-pattern (re-pattern "[\\p{Z}\\p{C}\\p{P}]+")) (def split-pattern (re-pattern "[\\p{Z}\\p{C}\\p{P}]+"))
(defn tokenize-line [line] (defn tokenize-line
"Tokenizes the line on split-pattern and returns a lazy seq of non-empty
tokens."
[line]
(->> line (split split-pattern) (filter (complement empty?)))) (->> line (split split-pattern) (filter (complement empty?))))
(defprotocol Processor (defprotocol Processor
(process [this tweet])) (process [this tweet]))
(defn twitter-stream-client [username password] (defn twitter-stream-client
"Creates an HttpClient for stream.twitter.com using the credentials provided."
[username password]
(doto (DefaultHttpClient.) (doto (DefaultHttpClient.)
(.. getCredentialsProvider (.. getCredentialsProvider
(setCredentials (setCredentials
(AuthScope. "stream.twitter.com" 80) (AuthScope. "stream.twitter.com" 80)
(UsernamePasswordCredentials. username password))))) (UsernamePasswordCredentials. username password)))))
(defn tweet-stream [^HttpClient client method & params] (defn tweet-stream
"Creates a lazy stream of live tweets."
[^HttpClient client method & params]
(let [read-line (fn this [^BufferedReader rdr] (let [read-line (fn this [^BufferedReader rdr]
(lazy-seq (lazy-seq
(if-let [line (.readLine rdr)] (if-let [line (.readLine rdr)]
@ -74,7 +85,9 @@
(throw (HttpException. (throw (HttpException.
(str "Invalid Status code: " status-code)))))) (str "Invalid Status code: " status-code))))))
(defn process-tweet-stream [stream processors] (defn process-tweet-stream
"Processes the tweet stream with the provided processors."
[stream processors]
(doseq [tweet stream] (doseq [tweet stream]
(future (doseq [p processors] (process p tweet))))) (future (doseq [p processors] (process p tweet)))))
@ -93,10 +106,10 @@
(def *tweet-window-size* 25) (def *tweet-window-size* 25)
(defn adjective-processor [adjective-map] (defn adjective-processor [adjective-map]
(let [states (atom (PersistentQueue/EMPTY))] (let [state-window (atom (PersistentQueue/EMPTY))]
(reify Processor (reify Processor
(process [this tweet] (process [this tweet]
(let [adj-typs (let [adj-typs ;list of types of adjective in the tweet
(->> tweet :text (->> tweet :text
tokenize-line tokenize-line
(map lower-case) (map lower-case)
@ -110,11 +123,17 @@
(reduce #(assoc %1 %2 (inc (get %1 %2 0))) {} adj-typs)] (reduce #(assoc %1 %2 (inc (get %1 %2 0))) {} adj-typs)]
(swap! adjective-type-count (swap! adjective-type-count
(fn [state] (fn [state]
(if (<= (count @states) *tweet-window-size*) ;If the count of states in the state-window is less than
(do (swap! states conj current-state) ;*tweet-window-size*, push the current-state in the
;state-window and return merge result: (state + current-state).
;Else, pop the oldest state from the state-window, push the
;current-state in the state-window and return merge result:
;(state + current-state - popped out oldest state).
(if (<= (count @state-window) *tweet-window-size*)
(do (swap! state-window conj current-state)
(merge-with + state current-state)) (merge-with + state current-state))
(let [old-state (peek @states)] (let [old-state (peek @state-window)]
(swap! states #(conj (pop %) current-state)) (swap! state-window #(conj (pop %) current-state))
(merge-with #(max 0 (- %1 %2)) (merge-with #(max 0 (- %1 %2))
(merge-with + state current-state) (merge-with + state current-state)
old-state)))))))))))) old-state))))))))))))

View File

@ -119,7 +119,11 @@
(.setSize dialog-width dialog-height)))) (.setSize dialog-width dialog-height))))
(defn init-gui [adjective-map] (defn init-gui [adjective-map]
(let [frame (JFrame. "Twitter Feelings") (let [frame (doto (JFrame. "Twitter Feelings")
(.setIconImage
(ImageIO/read (resource "clj_twitter_feelings/favicon.jpg")))
(.setDefaultCloseOperation WindowConstants/EXIT_ON_CLOSE)
(.setResizable false))
adjective-types (sort (keys @adjective-type-count)) adjective-types (sort (keys @adjective-type-count))
^DefaultPieDataset pie-dataset ^DefaultPieDataset pie-dataset
@ -164,9 +168,11 @@
"Credentials" "Input your Twitter credentials" 220 150 "Credentials" "Input your Twitter credentials" 220 150
"Screen Name" "Password" 20 "Screen Name" "Password" 20
"OK" "Cancel" "OK" "Cancel"
;validation-fn
(fn [uname pass _] (fn [uname pass _]
(when (or (empty? uname) (empty? pass)) (when (or (empty? uname) (empty? pass))
(str "Please input Screen Name and Password"))) (str "Please input Screen Name and Password")))
;ok-fn
(fn [uname pass ^JDialog dialog] (fn [uname pass ^JDialog dialog]
(future (future
(try (try
@ -181,13 +187,18 @@
"Error" :error) "Error" :error)
(.setVisible dialog true))))) (.setVisible dialog true)))))
(.start timer)) (.start timer))
;cancel-fn
(fn [_] (exit-app frame)))] (fn [_] (exit-app frame)))]
;add watches
(add-watch adjective-seen :adjective-lbl (add-watch adjective-seen :adjective-lbl
(fn [_ _ _ n] (fn [_ _ _ n]
(do-swing (do-swing
(.setText adjective-lbl (str "<html><h2>" n "</h2></html>"))))) (.setText adjective-lbl (str "<html><h2>" n "</h2></html>")))))
(add-watch status-seen :status-lbl (add-watch status-seen :status-lbl
(fn [_ _ _ n] (do-swing (.setText status-lbl n)))) (fn [_ _ _ n] (do-swing (.setText status-lbl n))))
;do some configuration of the plots
(doto ^PiePlot (.getPlot pie-chart) (doto ^PiePlot (.getPlot pie-chart)
(.setNoDataMessage "No data available") (.setNoDataMessage "No data available")
(.setLabelGenerator (StandardPieSectionLabelGenerator. "{0} {2}")) (.setLabelGenerator (StandardPieSectionLabelGenerator. "{0} {2}"))
@ -199,11 +210,9 @@
(.setFixedAutoRange 120000.0)) (.setFixedAutoRange 120000.0))
(doto (.. time-series-chart getXYPlot getRangeAxis) (doto (.. time-series-chart getXYPlot getRangeAxis)
(.setRange 0.0 100.0)) (.setRange 0.0 100.0))
;layout the content in the frame and make it visible
(doto frame (doto frame
(.setIconImage
(ImageIO/read (resource "clj_twitter_feelings/favicon.jpg")))
(.setDefaultCloseOperation WindowConstants/EXIT_ON_CLOSE)
(.setResizable false)
(.setContentPane (.setContentPane
(miglayout (JPanel.) (miglayout (JPanel.)
:layout [:wrap 1] :layout [:wrap 1]
@ -217,6 +226,8 @@
(.pack) (.pack)
(.setVisible true) (.setVisible true)
(RefineryUtilities/centerFrameOnScreen)) (RefineryUtilities/centerFrameOnScreen))
;show the auth-input-dialog
(doto auth-input-dialog (doto auth-input-dialog
(RefineryUtilities/centerFrameOnScreen) (RefineryUtilities/centerFrameOnScreen)
(.setVisible true)))) (.setVisible true))))