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?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 😄 🙏
you can add (s/tranformed [:usage] #(select-keys % [:total_tokens])) to you path. I'm not sure specter is the right approach
Pretty much the same thing…
(select-one [:openai-response
(submap [:created :usage])
(view
(fn [m]
(update m :usage
#(select-keys % [:total_tokens]))))])Another try
(->> m
(select
[:openai-response
(multi-path
(submap [:created])
[(submap [:usage])
(transformed :usage
#(select-one (submap [:total_tokens]) %))])])
(apply merge)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}}))