defmodule ProdopsEx.Artifact do @moduledoc """ Handles artifact operations for the ProdOps API such as retrieving artifacts for a given project, creating artifacts, refining artifacts, and deleting artifacts. Artifacts are any generated content, i.e. user stories, blog posts, code snippets, etc. They are organized by `artifact_slug`s, which define what type of content they are. Most artifact operations require specifying the `artifact_slug`. They are generated by passing input into a prompt template. Inputs come from up to three places: - user inputs: you can specify what values these have when creating Artifacts - document queries: semantically similar parts of documents are automatically found within a collection of documents, and inserted into the prompt template prior to generation, known as Retrieval-Augmented Generation (RAG) - document attachments: an entire document, such as something uploaded by you, is inserted into the prompt template prior to generation """ alias ProdopsEx.Client alias ProdopsEx.Config @base_path "/api/v1/artifact_types" defp url(config) do config[:api_url] <> @base_path end @doc """ Retrieves artifacts of one type based on the `artifact_slug` for a given project. ## Parameters - `project_id`: the ID of the project - `artifact_slug`: the slug which defines the type of artifacts that will be returned - `config` (optional): a configuration map used to override default config values ## Example iex> ProdopsEx.Artifact.list_project_artifacts(1, "story") {:ok, %{ status: "ok", response: %{ "artifacts" => [ %{ "chat_history" => [ %{ "content" => "You are going to be a product manager and write a BDD-style user story...", "role" => "user" }, %{ "content" => "## Background ...", "role" => "assistant" } ], "content" => "## Background ...", "id" => 1, "manually_edited" => false, "name" => "Artifact Name", "notes" => nil, "share_token" => nil } ] } }} ## Returns The function returns a list of artifacts for the specified project which match the artifact slug. """ @spec list_project_artifacts(integer(), String.t(), Keyword.t()) :: {:ok, list} | {:error, any} def list_project_artifacts(project_id, artifact_slug, config \\ []) when is_integer(project_id) and is_binary(artifact_slug) do config = Config.resolve_config(config) endpoint = url(config) path = "/#{artifact_slug}/artifacts?project_id=#{project_id}" Client.api_get(endpoint <> path, config) end @doc """ Creates an artifact by submitting a request with the required parameters. ## Parameters - `params`: The parameters for the artifact request. - `config` (optional): a configuration map used to override default config values ## Examples iex> ProdopsEx.Artifact.create(%{ ...> prompt_template_id: 2, ...> artifact_slug: "story", ...> project_id: 1, ...> inputs: [ ...> %{name: "Context", value: "this is a test"} ...> ], ...> fire_and_forget: true ...> }) {:ok, %{"artifact_id" => 123, "status" => "created"}} """ @spec create( %{ prompt_template_id: integer(), artifact_slug: String.t(), project_id: integer(), inputs: list(), fire_and_forget: boolean() }, Keyword.t() ) :: {:ok, map()} | {:error, term()} def create( %{prompt_template_id: prompt_template_id, artifact_slug: artifact_slug, project_id: project_id} = params, config \\ [] ) do config = Config.resolve_config(config) url = url(config) path = "/#{artifact_slug}/artifacts?project_id=#{project_id}" fire_and_forget = Map.get(params, :fire_and_forget, false) inputs = Map.get(params, :inputs, []) body = %{prompt_template_id: prompt_template_id, inputs: inputs, fire_and_forget: fire_and_forget} Client.api_post(url <> path, body, config) end @doc """ Retrieves an artifact by its ID. ## Parameters - `artifact_id`: the ID of the artifact - `artifact_slug`: the slug which defines the type of artifact that will be returned - `config` (optional): a configuration map used to override default config values ## Example iex> ProdopsEx.Artifact.get(1, "story") {:ok, %{ status: "ok", response: %{ "artifact" => %{ "chat_history" => [ %{ "content" => "some user prompt content", "role" => "user" }, %{ "content" => "some assistant response content", "role" => "assistant" } ], "id" => 123, "manually_edited" => false, "name" => "Some Name", "notes" => nil, "share_token" => nil } } }} """ @spec get(integer(), String.t(), Keyword.t()) :: {:ok, map} | {:error, any} def get(artifact_id, artifact_slug, config \\ []) when is_integer(artifact_id) and is_binary(artifact_slug) do config = Config.resolve_config(config) endpoint = url(config) <> "/#{artifact_slug}/artifacts/#{artifact_id}" Client.api_get(endpoint, config) end @doc """ Deletes an artifact by its ID. ## Parameters - `artifact_id`: the ID of the artifact - `artifact_slug`: the type of the artifact to be deleted - `config` (optional): a configuration map used to override default config values ## Example iex> ProdopsEx.Artifact.delete(1, "story") {:ok, %{status: "ok", response: %{"message" => "Artifact deleted successfully."}}} """ @spec delete(integer(), String.t(), Keyword.t()) :: {:ok, map} | {:error, any} def delete(artifact_id, artifact_slug, config \\ []) when is_integer(artifact_id) and is_binary(artifact_slug) do config = Config.resolve_config(config) endpoint = url(config) <> "/#{artifact_slug}/artifacts/#{artifact_id}" Client.api_delete(endpoint, config) end @doc """ Refines an artifact by submitting a request with the required parameters. ## Parameters - `params`: The parameters for the artifact request. - `config`: The configuration map containing the API key and optionally the URL. ## Example iex> ProdopsEx.Artifact.refine_artifact(%{ ...> artifact_id: 1, ...> artifact_slug: "story", ...> refine_prompt: "Refine this story" ...> }) """ @spec refine_artifact( %{ artifact_id: integer(), artifact_slug: String.t(), refine_prompt: String.t() }, Keyword.t() ) :: {:ok, map} | {:error, any} def refine_artifact(%{artifact_slug: artifact_slug, artifact_id: artifact_id} = params, config \\ []) do config = Config.resolve_config(config) url = url(config) <> "/#{artifact_slug}/artifacts/#{artifact_id}/refine" Client.api_post(url, params, config) end @doc """ Refines an artifact by submitting a request with the required parameters. ## Parameters - `params`: The parameters for the artifact request. - `config`: The configuration map containing the API key and endpoint URL. ## Example iex> ProdopsEx.Artifact.stream_refine_artifact(%{artifact_slug: "story", artifact_id: 1, refine_prompt: "some prompt"}) """ @spec stream_refine_artifact(map, Keyword.t()) :: {:ok, map} | {:error, any} def stream_refine_artifact(params, config \\ []) do config = Config.resolve_config(config) %{artifact_slug: artifact_slug, artifact_id: artifact_id, refine_prompt: refine_prompt} = params endpoint = url(config) <> "/#{artifact_slug}/artifacts/#{artifact_id}/refine_stream" body = %{artifact_slug: artifact_slug, artifact_id: artifact_id, refine_prompt: refine_prompt, stream: true} Client.api_post(endpoint, body, config) end @doc """ Creates an artifact by submitting a request with the required parameters. ## Parameters - `params`: The parameters for the artifact creation request. - `config`: The configuration map containing the API key and endpoint URL. ## Example iex> ProdopsEx.Artifact.stream_create_artifact(%{ ...> prompt_template_id: 2, ...> project_id: 1, ...> artifact_slug: "story", ...> inputs: [ ...> %{name: "Context", value: "this is a test"} ...> ] ...> }) """ @spec stream_create_artifact(map, Keyword.t()) :: {:ok, map} | {:error, any} def stream_create_artifact(params, config \\ []) do config = Config.resolve_config(config) %{artifact_slug: artifact_slug, prompt_template_id: prompt_template_id, project_id: project_id} = params endpoint = url(config) <> "/#{artifact_slug}/artifacts/stream?project_id=#{project_id}" inputs = Map.get(params, :inputs, []) body = %{prompt_template_id: prompt_template_id, inputs: inputs, stream: true} Client.api_post(endpoint, body, config) end end