travisshears revidoval tento gist . Přejít na revizi
1 file changed, 104 insertions
blue_sky.clj(vytvořil soubor)
@@ -0,0 +1,104 @@ | |||
1 | + | (ns micro-blog.blue-sky | |
2 | + | (:require | |
3 | + | [clj-http.client :as http-client] | |
4 | + | [micro-blog.pocket-base :as pb] | |
5 | + | [micro-blog.utils :as utils] | |
6 | + | [micro-blog.is-tech] | |
7 | + | [taoensso.telemere :as tel] | |
8 | + | [micro-blog.config :refer [config]])) | |
9 | + | ||
10 | + | (defn create-session [] | |
11 | + | (let [identifier (@config :blue-sky-username) | |
12 | + | api-key (@config :blue-sky-api-key) | |
13 | + | body {:identifier identifier :password api-key} | |
14 | + | url (str (@config :blue-sky-host) "/com.atproto.server.createSession") | |
15 | + | res-schema [:map | |
16 | + | [:did string?] | |
17 | + | [:accessJwt string?]]] | |
18 | + | (-> (http-client/post url | |
19 | + | {:form-params body | |
20 | + | :content-type :json | |
21 | + | :as :json}) | |
22 | + | :body | |
23 | + | (utils/validate-with-throw res-schema) | |
24 | + | (#(assoc % :access-jwt (:accessJwt %))) | |
25 | + | (select-keys [:did :access-jwt])))) | |
26 | + | ||
27 | + | (def post-res-schema [:map | |
28 | + | [:cursor [:maybe :string]] | |
29 | + | [:feed [:vector | |
30 | + | [:map [:post [:map | |
31 | + | [:cid :string] | |
32 | + | [:author [:map | |
33 | + | [:handle :string]]] | |
34 | + | ||
35 | + | [:embed {:optional true} | |
36 | + | [:map [:images {:optional true} [:vector [:map | |
37 | + | [:fullsize :string] | |
38 | + | [:alt :string]]]]]] | |
39 | + | [:record [:map | |
40 | + | [:facets {:optional true} [:vector [:map | |
41 | + | [:features [:vector [:map | |
42 | + | [:$type :string] | |
43 | + | [:tag {:optional true} [:maybe :string]]]]]]]] | |
44 | + | [:createdAt :string]]]]]]]]]) | |
45 | + | ||
46 | + | (defn get-posts-until-id | |
47 | + | ([session id] (get-posts-until-id session id nil [])) | |
48 | + | ([session id cursor prev-posts] | |
49 | + | (tel/log! {:level :info :data {:postId (:remoteId id)}} "Getting posts until id") | |
50 | + | (let [limit 5 | |
51 | + | body | |
52 | + | (-> (http-client/get (str (@config :blue-sky-host) "/app.bsky.feed.getAuthorFeed") | |
53 | + | {:headers {"Authorization" (str "Bearer " (session :access-jwt))} | |
54 | + | :query-params (cond-> {:actor (:did session) | |
55 | + | :limit limit} | |
56 | + | cursor (assoc :cursor cursor)) | |
57 | + | :content-type :json | |
58 | + | :as :json}) | |
59 | + | :body | |
60 | + | (utils/validate-with-throw post-res-schema)) | |
61 | + | posts (map :post (:feed body)) | |
62 | + | new-cursor (:cursor body) | |
63 | + | new-posts (take-while #(not= (:cid %) id) posts) | |
64 | + | new-and-prev-posts (concat new-posts prev-posts)] | |
65 | + | (cond | |
66 | + | ;; end of posts | |
67 | + | (not= (count posts) limit) new-and-prev-posts | |
68 | + | ;; found post | |
69 | + | (some #(= id (:cid %)) posts) new-and-prev-posts | |
70 | + | ;; recur | |
71 | + | :else (recur session id new-cursor new-and-prev-posts))))) | |
72 | + | ||
73 | + | (defn extract-tags [post] | |
74 | + | (let [facets (get (post :record) :facets []) | |
75 | + | features (flatten (map :features facets)) | |
76 | + | tag-features (filter #(= (:$type %) "app.bsky.richtext.facet#tag") features) | |
77 | + | tags (map :tag tag-features)] | |
78 | + | tags)) | |
79 | + | ||
80 | + | (defn extract-images [post] | |
81 | + | (let [images (get-in post [:embed :images] [])] | |
82 | + | (map #(vector (:fullsize %) (:alt %)) images))) | |
83 | + | ||
84 | + | (defn transform-post [post] | |
85 | + | (hash-map :source :blue_sky | |
86 | + | :fullPost post | |
87 | + | :remoteId (:cid post) | |
88 | + | :isTech (micro-blog.is-tech/is-tech? (:record post)) | |
89 | + | :authorId (get-in post [:author :handle]) | |
90 | + | :tags (extract-tags post) | |
91 | + | :images (extract-images post) | |
92 | + | :posted (get-in post [:record :createdAt]))) | |
93 | + | ||
94 | + | (defn save-post [post] | |
95 | + | (tel/log! {:level :info :data {:postId (:remoteId post)}} "Saving post") | |
96 | + | (pb/save-post post)) | |
97 | + | ||
98 | + | (defn run [] | |
99 | + | (tel/log! :info "Running blue sky fetcher") | |
100 | + | (let [session (create-session) | |
101 | + | last-saved-id (pb/get-latest-post-remote-id-by-source :blue_sky) | |
102 | + | new-posts (reverse (get-posts-until-id session last-saved-id))] | |
103 | + | (doseq [post new-posts] | |
104 | + | (-> post transform-post save-post)))) |
travisshears revidoval tento gist . Přejít na revizi
Žádné změny
travisshears revidoval tento gist . Přejít na revizi
1 file changed, 25 insertions
is_tech.clj(vytvořil soubor)
@@ -0,0 +1,25 @@ | |||
1 | + | (ns micro-blog.is-tech | |
2 | + | (:require | |
3 | + | [micro-blog.config :refer [config]] | |
4 | + | [taoensso.telemere :as tel] | |
5 | + | [clj-http.client :as client])) | |
6 | + | ||
7 | + | (defn is-tech? [post-text] | |
8 | + | (let [url (str (:mistral-host @config) "/v1/conversations") | |
9 | + | headers {"Content-Type" "application/json" | |
10 | + | "Accept" "application/json" | |
11 | + | "Authorization" (str "Bearer " (@config :mistral-api-key))} | |
12 | + | body {:inputs post-text | |
13 | + | :stream false | |
14 | + | :agent_id (@config :mistral-agent-id)}] | |
15 | + | (tel/log! {:level :info :data {:url url :agent_id (:agent_id body)}} "making request to mistral agent") | |
16 | + | (-> | |
17 | + | (client/post url {:headers headers | |
18 | + | :form-params body | |
19 | + | :content-type :json | |
20 | + | :as :json}) | |
21 | + | :body | |
22 | + | :outputs | |
23 | + | first | |
24 | + | :content | |
25 | + | (#(if (= "1" %) true false))))) |