(gptel-make-tool
:name "search_local_db"
:function (lambda (&rest args) (gptel--json-encode
(vconcat (apply #'my/gptel-wombag-search args)
(apply #'my/gptel-elfeed-search args))))
:description "Query the user's Elfeed and read-it-later databases containing RSS feed entries and saved articles respectively. Return an array of feed entries, each of which is a JSON object containing the following fields:
\"title\": the title of the feed entry
\"feed-title\": the name of the feed
\"url\": A web link to the entry
\"date\": The date the entry was published, in YYYY-MM-DD format
\"content\": The content of the entry. This is optional, not all entries have content."
:args (list '(:name "query"
:description "A space separated string of query terms. For example, \"programming elixir beam\""
:type "string")
'(:name "isVideo"
:description "A boolean indicating if the query is for videos."
:type "boolean")
'(:name "daterange"
:description "A range of publication dates to search between, in the format YYYY-MM-DD--YYYY-MM-DD.
For example, \"2023-12-01--2024-01-10\"."
:type "string"
:optional t)
'(:name "feed_title"
:description "feed-title to restrict searches to."
:type "string"
:optional t))
:category "local search")
(defun my/gptel-wombag-search (query-multiple _is-video &optional daterange feed-title)
(let ((num 5))
(thread-last
(split-string query-multiple)
(mapcan
(lambda (query)
(let* ((wombag-search-filter
(concat (format "#%d *%s " (max 2 (cl-decf num)) query)
(when daterange (format "@%s " daterange))
(when feed-title (format "^%s " feedtitle))))
(filter (wombag-search-parse-filter
wombag-search-filter wombag-search-columns))
(entries (wombag-db-get-entries filter wombag-search-columns)))
(when entries
(cl-loop for entry in entries
for id = (alist-get 'id entry)
collect
(nconc
(list :title (or (alist-get 'title entry) "NO TITLE")
:feed-title (or (alist-get 'domain_name entry) "")
:url (alist-get 'url entry)
:date (or (alist-get 'published_at entry)
(alist-get 'created_at entry)))
(list :content
(if-let ((content (car
(car-safe
(wombag-db-query `[:select content :from items :where (= id ,id)])))))
(with-temp-buffer
(insert content)
(shr-render-region (point-min) (point-max))
(buffer-substring-no-properties (point-min) (point-max)))))))))))
(vconcat))))
(defun my/gptel-elfeed-search (query-multiple is-video &optional daterange feed-title)
(let ((num 5))
(thread-last
(split-string query-multiple)
(mapcan
(lambda (query)
(let* ((elfeed-search-filter
(concat (format "#%d " (max 2 (cl-decf num))) query " "
(when daterange (format "@%s " daterange))
(when feed-title (format "=%s " feedtitle))
(when (and is-video (not (eq is-video :json-false))) "+youtube ")))
(filter (elfeed-search-parse-filter elfeed-search-filter))
(head (list nil)) (tail head) (count 0)
(lexical-binding t)
(search-func (byte-compile (elfeed-search-compile-filter filter))))
(with-elfeed-db-visit (entry feed)
(when (funcall search-func entry feed count)
(setf (cdr tail) (list entry)
tail (cdr tail)
count (1+ count))))
(when-let ((entries (cdr head)))
(cl-loop
for entry in entries
for feed = (elfeed-entry-feed entry)
collect
(nconc
(list :title (or (elfeed-meta entry :title) (elfeed-entry-title entry) "")
:feed-title (or (elfeed-meta feed :title) (elfeed-feed-title feed))
:url (elfeed-entry-link entry)
:date (format-time-string "%Y-%m-%d" (elfeed-entry-date entry)))
(when-let* ((ref (elfeed-entry-content entry))
(html (elfeed-deref ref)))
(list :content
(with-temp-buffer
(insert html)
(shr-render-region (point-min) (point-max))
(buffer-substring-no-properties (point-min) (point-max)))))))))))
(vconcat))))