lib/deployments.ex

defmodule Replicate.Deployments do
  @moduledoc """
  Documentation for `Predictions`.
  """
  @behaviour Replicate.Deployments.Behaviour
  @replicate_client Application.compile_env(:replicate, :replicate_client, Replicate.Client)

  alias Replicate.Deployments.Deployment
  alias Replicate.Predictions.Prediction

  @doc """
  Gets a deployment by name, in the format `owner/model-name`.

  ## Examples

  ```
  iex> {:ok, deployment} = Replicate.Deployments.get("test/model")
  iex> deployment.username
  "test"

  iex> Replicate.Predictions.get("not_a_real_id")
  {:error, "Not found"}
  ```
  """
  def get(name) do
    [owner, model_name] = String.split(name, "/")
    {:ok, %Deployment{username: owner, name: model_name}}
  end

  @doc """
  Create a new prediction with the deployment. The input parameter should be a map of the model inputs.

  ## Examples

  ```
  iex> {:ok, deployment} = Replicate.Deployments.get("test/model")
  iex> {:ok, prediction} = Replicate.Deployments.create_prediction(deployment, %{prompt: "a 19th century portrait of a wombat gentleman"})
  iex> prediction.status
  "starting"
  ```
  """
  def create_prediction(
        %Deployment{username: username, name: name},
        input,
        webhook \\ nil,
        webhook_completed \\ nil,
        webhook_event_filter \\ nil,
        stream \\ nil
      ) do
    webhook_parameters =
      %{
        "webhook" => webhook,
        "webhook_completed" => webhook_completed,
        "webhook_event_filter" => webhook_event_filter,
        "stream" => stream
      }
      |> Enum.filter(fn {_key, value} -> !is_nil(value) end)
      |> Enum.into(%{})

    body =
      %{
        "input" => input |> Enum.into(%{})
      }
      |> Map.merge(webhook_parameters)
      |> Jason.encode!()

    @replicate_client.request(:post, "/v1/deployments/#{username}/#{name}/predictions", body)
    |> parse_response()
  end

  defp parse_response({:ok, json_body}) do
    body =
      json_body
      |> Jason.decode!()
      |> string_to_atom()

    {:ok, struct(Prediction, body)}
  end

  defp parse_response({:error, message}), do: {:error, message}

  defp string_to_atom(body) do
    for {k, v} <- body, into: %{}, do: {String.to_atom(k), v}
  end
end