Fork me on GitHub
#specter
<
2023-04-18
>
h0bbit09:04:45

I’m trying to understand how I would use specter as a replacement for complex select-keys commands. For example, from the following payload:

{:fn "get-openai-reply",
 :openai-response
 {:created 1681730312,
  :choices
  [{:finish_reason "stop",
    :index 0,
    :message
    {:role "assistant",
     :content
     "Great! If you have any more questions, feel free to ask."}}],
  :usage
  {:total_tokens 788, :completion_tokens 14, :prompt_tokens 774},
  :id "chatcmpl-76HAObDzLQB58BILV05rQvhoCLd3Z",
  :object "chat.completion",
  :model "gpt-3.5-turbo-0301"}}
I want to extract the following output:
{:created 1681730312, :usage {:total_tokens 788}}
The following command:
(s/select-first [:openai-response (s/submap [:created :usage])] data) 
gives me:
{:created 1681730312, :usage {:total_tokens 788, :completion_tokens 14, :prompt_tokens 774}}
How do I get the last bit of the selection?

rolt14:04:00

you can add (s/tranformed [:usage] #(select-keys % [:total_tokens])) to you path. I'm not sure specter is the right approach

chromalchemy17:04:13

Pretty much the same thing…

(select-one [:openai-response 
               (submap [:created :usage])
               (view
                 (fn [m] 
                   (update m :usage
                     #(select-keys % [:total_tokens]))))])

chromalchemy17:04:36

Another try

(->> m
  (select
    [:openai-response
     (multi-path
       (submap [:created])
       [(submap [:usage]) 
        (transformed :usage 
          #(select-one (submap [:total_tokens]) %))])])
  (apply merge)

chromalchemy17:04:13

Probably more clear to transform from the start, instead of expecting to stack a bunch of localized selections in one path.

(transform 
    [(collect-one :openai-response :created)
     (collect-one :openai-response :usage :total_tokens)]
    (fn [created total m]
      {:created created
       :usage {:total_tokens total}}))

h0bbit05:04:04

hmm.. thanks folks.. I think doing a two step select-keys + dissoc is actually more readable in this case. I wanted to understand the different ways I could use specter, and your answers are fantastic in that regard 😄 🙏