added comments; some refactoring
parent
0bb5911351
commit
63635873ca
|
@ -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))))))))))))
|
||||||
|
|
|
@ -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))))
|
||||||
|
|
Loading…
Reference in New Issue