Skip to content

danielsz/cohere-clojure

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

https://img.shields.io/clojars/v/org.clojars.danielsz/cohere.svg

Cohere Clojure SDK

Cohere helps businesses explore, generate, search for, and act upon information…

In other words, Cohere provides NLP services such as text generation, classification, clustering, semantic search, automatic summarization, etc.

Motivation

Cohere’s platform exposes its functionality through a REST API and several SDKs. There is no Clojure SDK (duh!), but Clojure is apt at handling REST APIs, so everything should be good, right? Actually, not all features are available via the REST API. For tasks like creating custom models (fine-tuning) or clustering jobs, Cohere refers users to their SDKs. Hence the current Clojure port.

As to the broader question of why Clojure in the context of NLP or data science in general, the folks at Scicloj have more to say about that. I’ll just mention quickly the functional paradigm, Lisp-style meta-programming and interactive development at the REPL.

Caveat Emptor

The effort behind this project is personal and in no way commissioned by Cohere. I am releasing it as Open Source with the same license as Cohere’s official SDK, the MIT license.

Design Philosophy

This project follows The Principle of Least Surprise. It doesn’t require separate documentation than that of the official API documentation. Cohere’s API translates one to one with the provided Clojure functions. All function calls take keyword arguments, resulting in the following syntax:

(generate :prompt "Explain to me how LLMs work" :temperature 1.5)

Which starting from Clojure 1.11 is equivalent to:

(generate {:prompt "Explain to me how LLMs work" :temperature 1.5})

In other words, you can pass a map, or individual keyword/value pairs.

Arguments are the same as in Cohere’s API, but keywordized, for example, num_generations becomes :num_generations.

Configuration

The user’s Cohere API key will be accessed via Java Properties. How they get there is up to the user. For example:

(System/setProperty "cohere.api.key" "XXX-XXX")

The Endpoints

  • generate
  • embed
  • classify
  • tokenize
  • detokenize
  • detect-language
  • summarize
  • rerank
  • finetune
  • chat
  • feedback
  • check-api-key

Learning through Examples

What follows is a distillation of Cohere’s platform from the perspective of the Clojure SDK. If you feel you’re missing context or background, please refer to Cohere’s tutorials. In particular, Cohere’s LLM University curriculum is very effective at bringing developers up to speed with the fundamentals of NLP and LLMs.

Reading through those examples is fine, but running them at a REPL is better. Emacs users, please note that you can run the source blocks directly within the README since it is written in literate Babel org-mode.

Generate

(require '[cohere.client :refer [generate]])

This endpoint generates realistic text conditioned on a given input.

OpenAI is the name that burst into public consciousness overnight, and the desire to compare the offering of contenders with it is only natural. In OpenAI’s quickstart, they state that:

OpenAI has trained cutting-edge language models that are very good at understanding and generating text.

The example chosen to demonstrate that capability is shown below.

(def openai-prompt (clojure.string/join "\n" ["Suggest three names for an animal that is a superhero."
                                             "Animal: Cat"
                                             "Names: Captain Sharpclaw, Agent Fluffball, The Incredible Feline"
                                             "Animal: Dog"
                                             "Names: Ruff the Protector, Wonder Canine, Sir Barks-a-Lot"
                                             "Animal: Horse"
                                             "Names:"]))

Let’s try this on Cohere’s platform.

(generate :prompt openai-prompt)
{:id "20161769-4efe-41cc-b8a5-3e11b959760b", :generations [{:id "9f8ff197-c397-4e25-9ed9-b88853affbd3", :text " Stallion Force, The Equine Avengers, Super Horse"}], :prompt "Suggest three names for an animal that is a superhero.\nAnimal: Cat\nNames: Captain Sharpclaw, Agent Fluffball, The Incredible Feline\nAnimal: Dog\nNames: Ruff the Protector, Wonder Canine, Sir Barks-a-Lot\nAnimal: Horse\nNames:", :meta {:api_version {:version "2022-12-06"}}}

Most Cohere’s endpoints are of the regular HTPP request/reponse type, but the generate endpoint can send its output over streaming HTTP. A JSON stream of events will be sent where the last one will contain the complete response, and a field called is_finished set to true.

(with-open [stream (generate :prompt "Please tell me how we got here." :stream true :max_tokens 1200)]
                 (doall (json/parsed-seq (io/reader stream) true)))
({:text " We", :is_finished false} {:text " are", :is_finished false} {:text " here", :is_finished false} {:text " in", :is_finished false} {:text " the", :is_finished false} {:text " present", :is_finished false} {:text " moment", :is_finished false} {:text ",", :is_finished false} {:text " which", :is_finished false} {:text " is", :is_finished false} {:text " the", :is_finished false} {:text " result", :is_finished false} {:text " of", :is_finished false} {:text " the", :is_finished false} {:text " past", :is_finished false} {:text ".", :is_finished false} {:text " The", :is_finished false} {:text " past", :is_finished false} {:text " is", :is_finished false} {:text " a", :is_finished false} {:text " series", :is_finished false} {:text " of", :is_finished false} {:text " events", :is_finished false} {:text " that", :is_finished false} {:text " have", :is_finished false} {:text " led", :is_finished false} {:text " up", :is_finished false} {:text " to", :is_finished false} {:text " the", :is_finished false} {:text " present", :is_finished false} {:text ".", :is_finished false} {:text " These", :is_finished false} {:text " events", :is_finished false} {:text " can", :is_finished false} {:text " be", :is_finished false} {:text " traced", :is_finished false} {:text " back", :is_finished false} {:text " to", :is_finished false} {:text " the", :is_finished false} {:text " beginning", :is_finished false} {:text " of", :is_finished false} {:text " time", :is_finished false} {:text ",", :is_finished false} {:text " when", :is_finished false} {:text " the", :is_finished false} {:text " universe", :is_finished false} {:text " was", :is_finished false} {:text " created", :is_finished false} {:text ".", :is_finished false} {:text "\n", :is_finished false} {:text "\n", :is_finished false} {:text "The", :is_finished false} {:text " events", :is_finished false} {:text " that", :is_finished false} {:text " led", :is_finished false} {:text " up", :is_finished false} {:text " to", :is_finished false} {:text " the", :is_finished false} {:text " present", :is_finished false} {:text " moment", :is_finished false} {:text " can", :is_finished false} {:text " be", :is_finished false} {:text " categorized", :is_finished false} {:text " into", :is_finished false} {:text " several", :is_finished false} {:text " stages", :is_finished false} {:text ".", :is_finished false} {:text " The", :is_finished false} {:text " first", :is_finished false} {:text " stage", :is_finished false} {:text " is", :is_finished false} {:text " the", :is_finished false} {:text " creation", :is_finished false} {:text " of", :is_finished false} {:text " the", :is_finished false} {:text " universe", :is_finished false} {:text ",", :is_finished false} {:text " which", :is_finished false} {:text " occurred", :is_finished false} {:text " approximately", :is_finished false} {:text " 13", :is_finished false} {:text ".", :is_finished false} {:text "7", :is_finished false} {:text " billion", :is_finished false} {:text " years", :is_finished false} {:text " ago", :is_finished false} {:text ".", :is_finished false} {:text " This", :is_finished false} {:text " was", :is_finished false} {:text " followed", :is_finished false} {:text " by", :is_finished false} {:text " the", :is_finished false} {:text " formation", :is_finished false} {:text " of", :is_finished false} {:text " galaxies", :is_finished false} {:text " and", :is_finished false} {:text " stars", :is_finished false} {:text ",", :is_finished false} {:text " which", :is_finished false} {:text " occurred", :is_finished false} {:text " approximately", :is_finished false} {:text " 4", :is_finished false} {:text ".", :is_finished false} {:text "6", :is_finished false} {:text " billion", :is_finished false} {:text " years", :is_finished false} {:text " ago", :is_finished false} {:text ".", :is_finished false} {:text "\n", :is_finished false} {:text "\n", :is_finished false} {:text "The", :is_finished false} {:text " next", :is_finished false} {:text " stage", :is_finished false} {:text " is", :is_finished false} {:text " the", :is_finished false} {:text " development", :is_finished false} {:text " of", :is_finished false} {:text " life", :is_finished false} {:text " on", :is_finished false} {:text " Earth", :is_finished false} {:text ",", :is_finished false} {:text " which", :is_finished false} {:text " occurred", :is_finished false} {:text " approximately", :is_finished false} {:text " 3", :is_finished false} {:text ".", :is_finished false} {:text "8", :is_finished false} {:text " billion", :is_finished false} {:text " years", :is_finished false} {:text " ago", :is_finished false} {:text ".", :is_finished false} {:text " This", :is_finished false} {:text " was", :is_finished false} {:text " followed", :is_finished false} {:text " by", :is_finished false} {:text " the", :is_finished false} {:text " evolution", :is_finished false} {:text " of", :is_finished false} {:text " humans", :is_finished false} {:text ",", :is_finished false} {:text " which", :is_finished false} {:text " occurred", :is_finished false} {:text " approximately", :is_finished false} {:text " 2", :is_finished false} {:text ".", :is_finished false} {:text "4", :is_finished false} {:text " million", :is_finished false} {:text " years", :is_finished false} {:text " ago", :is_finished false} {:text ".", :is_finished false} {:text "\n", :is_finished false} {:text "\n", :is_finished false} {:text "The", :is_finished false} {:text " final", :is_finished false} {:text " stage", :is_finished false} {:text " is", :is_finished false} {:text " the", :is_finished false} {:text " development", :is_finished false} {:text " of", :is_finished false} {:text " technology", :is_finished false} {:text ",", :is_finished false} {:text " which", :is_finished false} {:text " has", :is_finished false} {:text " occurred", :is_finished false} {:text " in", :is_finished false} {:text " the", :is_finished false} {:text " past", :is_finished false} {:text " few", :is_finished false} {:text " thousand", :is_finished false} {:text " years", :is_finished false} {:text ".", :is_finished false} {:text " This", :is_finished false} {:text " has", :is_finished false} {:text " led", :is_finished false} {:text " to", :is_finished false} {:text " the", :is_finished false} {:text " creation", :is_finished false} {:text " of", :is_finished false} {:text " machines", :is_finished false} {:text ",", :is_finished false} {:text " which", :is_finished false} {:text " have", :is_finished false} {:text " made", :is_finished false} {:text " it", :is_finished false} {:text " possible", :is_finished false} {:text " for", :is_finished false} {:text " humans", :is_finished false} {:text " to", :is_finished false} {:text " travel", :is_finished false} {:text " to", :is_finished false} {:text " other", :is_finished false} {:text " planets", :is_finished false} {:text " and", :is_finished false} {:text " explore", :is_finished false} {:text " space", :is_finished false} {:text ".", :is_finished false} {:text "\n", :is_finished false} {:text "\n", :is_finished false} {:text "We", :is_finished false} {:text " are", :is_finished false} {:text " here", :is_finished false} {:text " in", :is_finished false} {:text " the", :is_finished false} {:text " present", :is_finished false} {:text " moment", :is_finished false} {:text " because", :is_finished false} {:text " of", :is_finished false} {:text " the", :is_finished false} {:text " events", :is_finished false} {:text " that", :is_finished false} {:text " have", :is_finished false} {:text " occurred", :is_finished false} {:text " in", :is_finished false} {:text " the", :is_finished false} {:text " past", :is_finished false} {:text ".", :is_finished false} {:text " These", :is_finished false} {:text " events", :is_finished false} {:text " have", :is_finished false} {:text " shaped", :is_finished false} {:text " the", :is_finished false} {:text " world", :is_finished false} {:text " and", :is_finished false} {:text " the", :is_finished false} {:text " lives", :is_finished false} {:text " of", :is_finished false} {:text " those", :is_finished false} {:text " who", :is_finished false} {:text " live", :is_finished false} {:text " in", :is_finished false} {:text " it", :is_finished false} {:text ".", :is_finished false} {:is_finished true, :finish_reason "COMPLETE", :response {:id "d903ed2d-c49a-497b-9165-96f2ea260113", :generations [{:id "40974223-228b-4d9f-87f6-696f77f44161", :text " We are here in the present moment, which is the result of the past. The past is a series of events that have led up to the present. These events can be traced back to the beginning of time, when the universe was created.\n\nThe events that led up to the present moment can be categorized into several stages. The first stage is the creation of the universe, which occurred approximately 13.7 billion years ago. This was followed by the formation of galaxies and stars, which occurred approximately 4.6 billion years ago.\n\nThe next stage is the development of life on Earth, which occurred approximately 3.8 billion years ago. This was followed by the evolution of humans, which occurred approximately 2.4 million years ago.\n\nThe final stage is the development of technology, which has occurred in the past few thousand years. This has led to the creation of machines, which have made it possible for humans to travel to other planets and explore space.\n\nWe are here in the present moment because of the events that have occurred in the past. These events have shaped the world and the lives of those who live in it.", :finish_reason "COMPLETE"}], :prompt "Please tell me how we got here."}})

If there is one application where generative AI is showing promise, it’s probably for generating copy.

(defn product [product] (str "Generate a social ad copy for the product: " product "."))
(generate :prompt (product "Wireless Earbuds"))
{:id "c85b68a6-eba7-471a-9a4a-ac413241dab6", :generations [{:id "3353ed15-058c-4b04-9562-207355351d5e", :text " Introducing our new wireless earbuds - the perfect accessory for all your on-the-go needs! Enjoy"}], :prompt "Generate a social ad copy for the product: Wireless Earbuds.", :meta {:api_version {:version "2022-12-06"}}}

Do we like the copy? If so, we can send our feedback.

(require '[cohere.client :refer [generate-feedback]])
(generate-feedback :request_id "3353ed15-058c-4b04-9562-207355351d5e" :good_response true)

This is how you would implement a thumbs-up element in the UI for assisted writing. As to the thumbs-down, the UI should provide an editable field with Cohere’s response. If the user edits the response, tweaks it, then we can send the modified response back to Cohere:

(def user-edited-response "Our new wireless earbuds are the perfect accessory for all your on-the-go needs! Enjoy!")
(generate-feedback :request_id "3353ed15-058c-4b04-9562-207355351d5e" :good_response false :desired_response user-edited-response)

But maybe what we had in mind was something else, maybe we wanted an ad copy that follows the AIDA hierarchical model. In that case, the user should be able to edit the prompt and provide more instructions.

(defn aida-framework [product] (str "Generate an ad copy for the product: " product ".

 The copy consists of four parts, following the AIDA Framework.
 1 - Attention
 2 - Interest
 3 - Desire
 4 - Action

 The copy for each part is clear and concise."))
(generate :prompt (aida-framework "Wireless Earbuds") :max_tokens 1200)
{:id "9fcf3b6e-7ff1-49cb-a515-4f78c02da400", :generations [{:id "7d9acdaa-213f-4659-97e8-d2911a0770b2", :text " ... \"Wireless Earbuds - The Perfect Companion for Your Daily Commute\"\n\n1. Attention:\n- \"Don't struggle with tangled cords and poor sound quality on your daily commute. Upgrade to wireless earbuds and enjoy crystal clear sound and comfortable, snug fit.\"\n\n2. Interest:\n- \"With wireless earbuds, you can take calls, listen to music, and podcasts without any distractions. The sleek design and comfortable fit make it the perfect companion for your daily commute.\"\n\n3. Desire:\n- \"Enjoy the freedom of wireless earbuds and make your daily commute more enjoyable. The easy-to-use design and crystal clear sound make it the perfect choice for anyone looking for a stylish and functional accessory.\"\n\n4. Action:\n- \"Try wireless earbuds today and experience the convenience and comfort for yourself. Order now and enjoy free shipping and easy returns.\""}], :prompt "Generate an ad copy for the product: Wireless Earbuds.\n\nThe copy consists of four parts, following the AIDA Framework.\n1 - Attention\n2 - Interest\n3 - Desire\n4 - Action\n\nThe copy for each part is clear and concise.", :meta {:api_version {:version "2022-12-06"}}}

Classify

(require '[cohere.client :refer [classify]])

LLMs have been pre-trained with a vast amount of training data, allowing them to capture how words are being used and how their meaning changes depending on the context. A very common application of this is text classification.

Let’s begin with sentiment analysis.

(def examples [{:text "I'm so proud of you" :label "positive"}
               {:text "What a great time to be aliveI'm so proud of you" :label "positive"}
               {:text "That's awesome work" :label "positive"}
               {:text "The service was amazing" :label "positive"}
               {:text "I love my family" :label "positive"}
               {:text "I hate this place" :label "negative"}
               {:text "The most ridiculous thing I've ever heard" :label "negative"}
               {:text "They don't care about me" :label "negative"}
               {:text "I am really frustrated" :label "negative"}
               {:text "They don't care about me" :label "negative"}
               {:text "This is so unfair" :label "negative"}
               {:text "This made me think" :label "neutral"}
               {:text "The good old days" :label "neutral"}
               {:text "What's the difference" :label "neutral"}
               {:text "You can't ignore this" :label "neutral"}
               {:text "That's how I see it" :label "neutral"}])

Let’s now set up our inputs to classify.

(def inputs ["Hello, world! What a beautiful day",
             "It was a great time with great people",
             "Great place to work",
             "That was a wonderful evening",
             "Maybe this is why",
             "Let's start again",
             "That's how I see it",
             "These are all facts",
             "This is the worst thing",
             "I cannot stand this any longer",
             "This is really annoying",
             "I am just plain fed up"
             ])

Ready to go!

(classify :inputs inputs :examples examples)
{:id "0b3d7a80-7d1f-4c0c-bf44-6c5930ee8310", :classifications [{:id "86710c33-becf-4f05-93b3-040175408036", :input "Hello, world! What a beautiful day", :prediction "positive", :confidence 0.67250913, :labels {:negative {:confidence 0.046673477}, :neutral {:confidence 0.2808174}, :positive {:confidence 0.67250913}}} {:id "2c66fa98-07d9-4ecc-8e3c-93ee54f5ab71", :input "It was a great time with great people", :prediction "positive", :confidence 0.98359793, :labels {:negative {:confidence 5.770475E-4}, :neutral {:confidence 0.015824998}, :positive {:confidence 0.98359793}}} {:id "cb9edbde-b96d-4ab3-8227-7596154d6177", :input "Great place to work", :prediction "positive", :confidence 0.8030995, :labels {:negative {:confidence 0.18620741}, :neutral {:confidence 0.010693076}, :positive {:confidence 0.8030995}}} {:id "ac653477-2fd0-425c-a4fa-058d844e7538", :input "That was a wonderful evening", :prediction "positive", :confidence 0.91828907, :labels {:negative {:confidence 0.0020052015}, :neutral {:confidence 0.07970571}, :positive {:confidence 0.91828907}}} {:id "cb0887b8-7257-4cd7-849f-b263dcd78dff", :input "Maybe this is why", :prediction "neutral", :confidence 0.72916573, :labels {:negative {:confidence 0.26635805}, :neutral {:confidence 0.72916573}, :positive {:confidence 0.0044762404}}} {:id "a32284d1-fdc8-412b-90d6-0323674f2582", :input "Let's start again", :prediction "neutral", :confidence 0.8327636, :labels {:negative {:confidence 0.14705248}, :neutral {:confidence 0.8327636}, :positive {:confidence 0.02018392}}} {:id "5b2f9505-99e2-4ef6-ba6a-cc62da879b71", :input "That's how I see it", :prediction "neutral", :confidence 0.999064, :labels {:negative {:confidence 5.462054E-4}, :neutral {:confidence 0.999064}, :positive {:confidence 3.897949E-4}}} {:id "495b0a9c-0ffc-4de9-982c-c972929110ea", :input "These are all facts", :prediction "neutral", :confidence 0.8203323, :labels {:negative {:confidence 0.12454694}, :neutral {:confidence 0.8203323}, :positive {:confidence 0.055120792}}} {:id "8a5789bb-02fb-489f-80ff-33e542fcaef8", :input "This is the worst thing", :prediction "negative", :confidence 0.92929465, :labels {:negative {:confidence 0.92929465}, :neutral {:confidence 0.06556252}, :positive {:confidence 0.0051428643}}} {:id "852b8ad6-8dd3-4343-bba8-649e21d77ff7", :input "I cannot stand this any longer", :prediction "negative", :confidence 0.92076635, :labels {:negative {:confidence 0.92076635}, :neutral {:confidence 0.074523635}, :positive {:confidence 0.004710017}}} {:id "78257bef-8c2e-45b8-aa25-68d1fad14b6f", :input "This is really annoying", :prediction "negative", :confidence 0.98556703, :labels {:negative {:confidence 0.98556703}, :neutral {:confidence 0.013624879}, :positive {:confidence 8.0808706E-4}}} {:id "ef9f8231-aa63-4be6-8799-d720cce7c401", :input "I am just plain fed up", :prediction "negative", :confidence 0.99926674, :labels {:negative {:confidence 0.99926674}, :neutral {:confidence 5.1193114E-4}, :positive {:confidence 2.2134688E-4}}}], :meta {:api_version {:version "2022-12-06"}}}

This is so much fun! Let’s do a spam filter now.

(def examples [{:text "Dermatologists don't like her!" :label "spam"}
               {:text "Hello, open to this?" :label "spam"}
               {:text "I need help please wire me $1000 right now" :label "spam"}
               {:text  "Nice to know you ;)" :label "spam"}
               {:text "Please help me?" :label "spam"}
               {:text "Your parcel will be delivered today" :label "not spam"}
               {:text "Review changes to our Terms and Conditions" :label "not spam"}
               {:text "Weekly sync notes" :label "not spam"}
               {:text  "Re: Follow up from today’s meeting" :label "not spam"}
               {:text  "Pre-read for tomorrow" :label "not spam"}])
(def inputs ["Confirm your email address"
             "hey i need u to send some $"])

Ready to go!

(classify :inputs inputs :examples examples)
{:id "a9d9b25e-a712-4f2e-8c1a-ad6dff1bac40", :classifications [{:id "7794dd61-463c-4ad0-b8e9-addd87fef64d", :input "Confirm your email address", :prediction "not spam", :confidence 0.8082329, :labels {:not spam {:confidence 0.8082329}, :spam {:confidence 0.19176713}}} {:id "75314f50-5620-497f-a557-092691565bf8", :input "hey i need u to send some $", :prediction "spam", :confidence 0.9893421, :labels {:not spam {:confidence 0.01065793}, :spam {:confidence 0.9893421}}}], :meta {:api_version {:version "2022-12-06"}}}

Custom models (fine-tuning)

(require '[cohere.finetune :refer [create-custom-model]]
         '[cohere.dataset :refer [jsonl-dataset]]
         '[cheshire.core :as json])

Cohere’s platform gives you the ability to train a Large Language Model (LLM) and customize it with a dataset to excel at a specific task. Custom models can lead to some of the best-performing NLP models for a wide number of tasks.

An example of such specialized tasks is a coding assistant. The ClojureLLM team curates data sources for the fine-tuning of an LLM for Clojure. If you clone their repository you will find a file in the data directory called clojure_llm_clojure_mailgroup_prompts_sample.json. It is a Json array made of Json objects where each object contains a prompt and a response field. We will need to slightly modify that format to accommodate Cohere’s requirements: the dataset needs to be in /Json Lines/ format.

(def json-file (io/file "path/to/clojure_llm_clojure_mailgroup_prompts_sample.json"))
(def jsonl-file (str (System/getProperty "java.io.tmpdir") "/" (.getName json-file) "l")
(defn json->jsonl [file]
  (let [data (json/parse-string (slurp json-file) true)]
    (doseq [line data]
      (spit jsonl-file (str (json/generate-string {:prompt (:prompt line) :completion (:response line )}) "\n") :append true))))
(json->jsonl json-file)
(def clojure-dataset (jsonl-dataset :train-file jsonl-file))
(create-custom-model "clojure-llm" :generative clojure-dataset {})

And now we can prompt the generative AI with our custom model.

(generate :model "40f8e1a2-09c7-4d58-a7f9-eae6b6b8c9fa-ft" :prompt "What is the difference between merge and assoc in Clojure?")
{:id "c6476cc5-6a36-4de4-b49b-c9d62d03e80b", :generations [{:id "9e56d8dc-beb7-47e9-bda1-71667b3c97af", :text " In Clojure, merge and assoc are both functions that are used to modify the value of a key in a map. However, there is a slight difference between the two functions. The merge function takes two maps as arguments and returns a new map with the union of the two maps. The assoc function takes a key and a value as arguments and returns a new map with the key added to the map. \n\nFor example, if you wanted to merge two maps, you could use the merge function. You could also use assoc to add a new key to a map."}], :prompt "What is the difference between merge and assoc in Clojure?", :meta {:api_version {:version "1"}}}

Chat

(require '[cohere.client :refer [chat]])
(chat :message "Hey! How are you doing today?")
{:response_id "accad3b5-e438-4804-971b-0a41aa973c97", :text "As a large language model, I don't have feelings, but I'm ready to help you with whatever you need!", :generation_id "92390c48-921e-489f-adce-9f08edcb0339", :token_count {:prompt_tokens 70, :response_tokens 24, :total_tokens 94}, :meta {:api_version {:version "1"}}}

Like generate, the chat endpoint supports streaming mode.

(require '[cheshire.core :as json]
         '[clojure.java.io :as io])
(with-open [stream (chat :message "Hey! How are you doing today?" :stream true)]
  (doall (json/parsed-seq (io/reader stream) true)))
({:is_finished false, :event_type "text-generation", :text "I"} {:is_finished false, :event_type "text-generation", :text "'m"} {:is_finished false, :event_type "text-generation", :text " doing"} {:is_finished false, :event_type "text-generation", :text " great"} {:is_finished false, :event_type "text-generation", :text "!"} {:is_finished false, :event_type "text-generation", :text " How"} {:is_finished false, :event_type "text-generation", :text " about"} {:is_finished false, :event_type "text-generation", :text " you"} {:is_finished false, :event_type "text-generation", :text "?"} {:is_finished true, :event_type "stream-end", :response {:response_id "eaf755b1-b753-40c6-a6c1-e1b1afc7ed8b", :text "I'm doing great! How about you?", :generation_id "8bed3a93-2f12-4bef-854d-2422beccd1e2", :token_count {:prompt_tokens 70, :response_tokens 9, :total_tokens 79}}, :finish_reason "COMPLETE"})

Sponsorship

The current state of the Cohere Clojure SDK is fairly comprehensive, but it is not exhaustive. The following endpoints are missing:

  • dataset
  • embed-jobs
  • cluster-jobs
  • embed-codebook

As it stands, that work is not a priority for me. Additionally, the Cohere Python SDK integrates with Read the Docs, which allows to generate a PDF with the documentation. That too isn’t on my priority list. With that being said, I welcome sponsors to fund the last-mile effort and bringing the Clojure SDK on parity with Cohere’s own SDKs.

About

Unofficial port of the Cohere SDK

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published