defmodule MistralClient do @moduledoc """ Provides API wrappers for Mistral API See https://docs.mistral.ai/api for further info on REST endpoints """ use Application alias MistralClient.Config alias MistralClient.Models alias MistralClient.Chat alias MistralClient.Embeddings def start(_type, _args) do children = [Config] opts = [strategy: :one_for_one, name: MistralClient.Supervisor] Supervisor.start_link(children, opts) end @doc """ Retrieve the list of available models ## Example request ```elixir MistralClient.models() ``` ## Example response ```elixir {:ok, %{ data: [ %{ "created" => 1702997889, "id" => "mistral-medium-latest", "object" => "model", "owned_by" => "mistralai", "parent" => nil, "permission" => [ %{ "allow_create_engine" => false, "allow_fine_tuning" => false, "allow_logprobs" => false, .... } ], "root" => nil } ] } } ``` See: https://docs.mistral.ai/api#operation/listModels """ def models(), do: Models.fetch() @doc """ Creates a completion for the chat message ## Example request ```elixir MistralClient.chat( "model": "open-mistral-7b", "messages": [ %{ "role": "user", "content": "What is the best French cheese?" } ] ) ``` ## Example response ```elixir {:ok, %{ choices: [ %{ "finish_reason" => "stop", "index" => 0, "message" => %{ "content" => "It's subjective to determine the 'best' French cheese as it depends on personal preferences. Here are some popular and highly regarded French cheeses in various categories:\n\n1. Soft and Bloomy Rind: Brie de Meaux or Brie de Melun, Camembert de Normandie\n2. Hard and Cooked: Comté, Gruyère\n3. Hard and Uncooked: Cheddar-like: Comté, Beaufort, Appenzeller-style: Vacherin Fribourgeois, Alpine-style: Reblochon\n4. Blue Cheese: Roquefort, Fourme d'Ambert\n5. Goat Cheese: Chavignol, Crottin de Chavignol, Sainte-Maure de Touraine\n\nHowever, I would recommend trying a variety of French cheeses to discover your favorite. It's an enjoyable and delicious experience!", "role" => "assistant" } } ], created: 1702997889, id: "cmpl-83f575cf654b4a83b99d342f644db292", model: "open-mistral-7b", object: "chat.completion", usage: %{ "completion_tokens" => 204, "prompt_tokens" => 15, "total_tokens" => 219 } } } ``` N.B. to use "stream" mode you must be set http_options as below when you want to treat the chat completion as a stream. You may also pass in the api_key in the same way, or define in the config.exs of your elixir project. ## Example request (stream) ```elixir MistralClient.chat( [ model: "open-mistral-7b", messages: [ %{role: "user", content: "What is the best French cheese?"} ], stream: true ], MistralClient.config(http_options: %{stream_to: self(), async: :once}) ) |> Stream.each(fn res -> IO.inspect(res) end) |> Stream.run() ``` ## Example response (stream) ```elixir %{ "choices" => [ %{"delta" => %{"role" => "assistant"}, "finish_reason" => nil, "index" => 0} ], "id" => "cmpl-9d2c56da16394e009cafbbde9cb5d725", "model" => "open-mistral-7b" } %{ "choices" => [ %{ "delta" => %{ "content" => "It's subjective to determine the 'best'", "role" => nil }, "finish_reason" => nil, "index" => 0 } ], "created" => 1702999980, "id" => "cmpl-9d2c56da16394e009cafbbde9cb5d725", "model" => "open-mistral-7b", "object" => "chat.completion.chunk" } %{ "choices" => [ %{ "delta" => %{ "content" => " French cheese as it largely depends on personal preferences. Here are a", "role" => nil }, "finish_reason" => nil, "index" => 0 } ], "created" => 1702999980, "id" => "cmpl-9d2c56da16394e009cafbbde9cb5d725", "model" => "open-mistral-7b", "object" => "chat.completion.chunk" } ``` See: https://docs.mistral.ai/api#operation/createChatCompletion for the complete list of parameters you can pass to the chat function """ def chat(params, config \\ Config.config(%{})) do Chat.fetch(params, config) end @doc """ Creates an embedding vector representing the input text. ## Example request ```elixir MistralClient.embeddings( model: "mistral-embed", input: [ "Embed this sentence.", "As well as this one." ] ) ``` ## Example response ```elixir {:ok, %{ data: [ %{ "embedding" => [-0.0165863037109375, 0.07012939453125, 0.031494140625, 0.013092041015625, 0.020416259765625, 0.00977325439453125, 0.0256195068359375, 0.0021114349365234375, -0.00867462158203125, -0.00876617431640625, -0.039520263671875, 0.058441162109375, -0.025390625, 0.00748443603515625, -0.0290679931640625, 0.040557861328125, 0.05474853515625, 0.0258636474609375, 0.031890869140625, 0.0230255126953125, -0.056427001953125, -0.01617431640625, -0.061248779296875, 0.012115478515625, -0.045745849609375, -0.0269622802734375, -0.0079498291015625, -0.03778076171875, -0.040008544921875, 8.23974609375e-4, 0.0242767333984375, -0.02996826171875, 0.0305023193359375, -0.0022830963134765625, -0.012237548828125, -0.036163330078125, -0.033172607421875, -0.044891357421875, 0.01326751708984375, 0.0021228790283203125, 0.00978851318359375, -2.1147727966308594e-4, -0.0305633544921875, -0.0230865478515625, -0.024932861328125, ...], "index" => 0, "object" => "embedding" }, %{ "embedding" => [-0.0234222412109375, 0.039337158203125, 0.052398681640625, -0.0183868408203125, 0.03399658203125, 0.003879547119140625, 0.024688720703125, -5.402565002441406e-4, -0.0119171142578125, -0.006988525390625, -0.0136260986328125, 0.041839599609375, -0.0274810791015625, -0.015411376953125, -0.041412353515625, 0.0305328369140625, 0.006023406982421875, 0.001140594482421875, -0.007167816162109375, 0.01085662841796875, -0.03668212890625, -0.033111572265625, -0.044586181640625, 0.020538330078125, -0.0423583984375, -0.03131103515625, -0.0119781494140625, -0.048736572265625, -0.0850830078125, 0.0203857421875, -0.0023899078369140625, -0.0249176025390625, 0.019500732421875, 0.007068634033203125, 0.0301055908203125, -0.041534423828125, -0.0255584716796875, -0.0246429443359375, 0.022674560546875, -2.760887145996094e-4, -0.015045166015625, -0.01788330078125, 0.0146484375, -0.005573272705078125, ...], "index" => 1, "object" => "embedding" } ], id: "embd-7d921a4410e249b9960195ab6705b255", model: "mistral-embed", object: "list", usage: %{ "completion_tokens" => 0, "prompt_tokens" => 15, "total_tokens" => 15 } }} ``` See: https://docs.mistral.ai/api#operation/createEmbedding """ def embeddings(params, config \\ Config.config(%{})) do Embeddings.fetch(params, config) end @doc """ Generates the config settings from the given params, using the defaults defined in the application's config.exs if not passed in params. ## Example request ```elixir MistralClient.config( api_key: "YOUR_MISTRAL_KEY", http_options: %{ stream_to: self(), async: :once } ) ``` """ def config(params) do opts = case params do params_list when is_list(params_list) -> Enum.into(params_list, %{}) _ -> params end Config.config(opts) end end