defmodule Replicate.Models do @moduledoc """ Documentation for `Models`. """ @behaviour Replicate.Models.Behaviour @replicate_client Application.compile_env(:replicate, :replicate_client, Replicate.Client) alias Replicate.Models.Model @doc """ Gets a model from a owner/name string. Raises an error if the model doesn't exist. ## Examples ``` iex> %Model{owner: owner, name: name} = Replicate.Models.get!("replicate/hello-world") iex> owner "replicate" iex> name "hello-world" ``` """ def get!(name) do [username, name] = String.split(name, "/") {:ok, result} = @replicate_client.request(:get, "/v1/models/#{username}/#{name}") model = Jason.decode!(result) |> string_to_atom() struct(Model, model) end @doc """ Gets a model from a owner/name string. Returns {:error, "Not found"} if the model doesn't exist. ## Examples ``` iex> {:ok, %Model{owner: owner, name: name}} = Replicate.Models.get("replicate/hello-world") iex> owner "replicate" iex> name "hello-world" ``` """ def get(name) do [username, name] = String.split(name, "/") case @replicate_client.request(:get, "/v1/models/#{username}/#{name}") do {:ok, result} -> model = Jason.decode!(result) |> string_to_atom() {:ok, struct(Model, model)} {:error, message} -> {:error, message} end end @doc """ Gets a version of a model. Raises an error if the version doesn't exist. ## Examples ``` iex> model = Replicate.Models.get!("replicate/hello-world") iex> version = Replicate.Models.get_version!(model, "v2") iex> version.id "v2" ``` """ def get_version!(%Model{owner: owner, name: name}, version) do {:ok, result} = @replicate_client.request(:get, "/v1/models/#{owner}/#{name}/versions/#{version}") version = Jason.decode!(result) |> string_to_atom() struct(Replicate.Models.Version, version) end @doc """ Gets the latest version of a model. Raises an error if the version doesn't exist. ## Examples ``` iex> model = Replicate.Models.get!("replicate/hello-world") iex> version = Replicate.Models.get_latest_version!(model) iex> version.id "v2" ``` """ def get_latest_version!(%Model{latest_version: %{"id" => id}} = model) do model |> get_version!(id) end @doc """ Returns a list of all versions for a model. ## Examples ``` iex> model = Replicate.Models.get!("replicate/hello-world") iex> versions = Replicate.Models.list_versions(model) iex> %Replicate.Models.Version{id: id, cog_version: cog_version} = List.first(versions) iex> id "v1" iex> cog_version "0.3.0" ``` """ def list_versions(%Model{owner: owner, name: name}) do case @replicate_client.request(:get, "/v1/models/#{owner}/#{name}/versions") do {:ok, results} -> %{"results" => versions} = Jason.decode!(results) versions |> Enum.map(fn v -> atom_map = string_to_atom(v) struct(Replicate.Models.Version, atom_map) end) {:error, message} -> raise message end end @doc """ Get a paginated list of all public models. ## Examples iex> %{next: next, previous: previous, results: results} = Replicate.Models.list() iex> next "https://api.replicate.com/v1/trainings?cursor=cD0yMDIyLTAxLTIxKzIzJTNBMTglM0EyNC41MzAzNTclMkIwMCUzQTAw" iex> previous nil iex> results |> length() 25 iex> results |> Enum.at(0) %Replicate.Models.Model{ url: "https://replicate.com/replicate/hello-world", owner: "replicate", name: "hello-world", description: "A tiny model that says hello", visibility: "public", github_url: "https://github.com/replicate/cog-examples", paper_url: nil, license_url: nil, run_count: 12345, cover_image_url: nil, default_example: nil, latest_version: %{ "cog_version" => "0.3.0", "created_at" => "2022-03-21T13:01:04.418669Z", "id" => "v2", "openapi_schema" => %{} } } """ def list() do case @replicate_client.request(:get, "/v1/models") do {:ok, response} -> %{"results" => results, "next" => next, "previous" => previous} = Jason.decode!(response) models = results |> Enum.map(fn m -> atom_map = string_to_atom(m) struct!(Model, atom_map) end) %{next: next, previous: previous, results: models} {:error, message} -> raise message end end @doc """ Create a model. Args: owner: The name of the user or organization that will own the model. name: The name of the model. visibility: Whether the model should be public or private. hardware: The SKU for the hardware used to run the model. Possible values can be found by calling `Replicate.Hardware.list()`. description: A description of the model. github_url: A URL for the model's source code on GitHub. paper_url: A URL for the model's paper. license_url: A URL for the model's license. cover_image_url: A URL for the model's cover image. Returns {:ok, %Replicate.Models.Model{}} or {:error, message}. ## Examples iex> {:ok, model} = Replicate.Models.create( ...> owner: "replicate", ...> name: "hello-world", ...> visibility: "public", ...> hardware: "gpu-a40-large" ...> ) iex> model.owner "replicate" """ def create(opts) do with {:ok, owner} <- Keyword.fetch(opts, :owner), {:ok, name} <- Keyword.fetch(opts, :name), {:ok, visibility} <- Keyword.fetch(opts, :visibility), {:ok, hardware} <- Keyword.fetch(opts, :hardware) do description = Keyword.get(opts, :description, nil) github_url = Keyword.get(opts, :github_url, nil) paper_url = Keyword.get(opts, :paper_url, nil) license_url = Keyword.get(opts, :license_url, nil) cover_image_url = Keyword.get(opts, :cover_image_url, nil) body = %{ "owner" => owner, "name" => name, "visibility" => visibility, "hardware" => hardware, "description" => description, "github_url" => github_url, "paper_url" => paper_url, "license_url" => license_url, "cover_image_url" => cover_image_url } |> Jason.encode!() case @replicate_client.request(:post, "/v1/models", body) do {:ok, result} -> model = Jason.decode!(result) |> string_to_atom() {:ok, struct(Model, model)} {:error, message} -> {:error, message} end else :error -> {:error, "A required parameter (owner/name/visiblity/hardware) is missing"} end end defp string_to_atom(body) do for {k, v} <- body, into: %{}, do: {String.to_atom(k), v} end end