Skip to content

Commit

Permalink
Dalle service (#98)
Browse files Browse the repository at this point in the history
* social share

* prompt function

* generate from form

* gen, confirm and redo prompt
  • Loading branch information
michelson authored Nov 7, 2022
1 parent ce3a081 commit b213068
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 12 deletions.
2 changes: 1 addition & 1 deletion config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ config :rauversion, tbk_commerce_id: System.get_env("TBK_COMMERCE_ID")
config :rauversion, tbk_api_key: System.get_env("TBK_API_KEY")
config :rauversion, platform_event_fee: System.get_env("PLATFORM_EVENTS_FEE")
config :rauversion, peaks_processor: System.get_env("PEAKS_PROCESSOR", "ffmpeg")

config :rauversion, :openai_api_key, System.get_env("OPENAI_API_KEY")
# config/runtime.exs is executed for all environments, including
# during releases. It is executed after compilation and before the
# system starts, so it is typically used to load production configuration
Expand Down
7 changes: 6 additions & 1 deletion lib/rauversion/blob_utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ defmodule Rauversion.BlobUtils do
Rauversion.BlobUtils.attach_file(struct, kind, blob)
end

def attach_file(struct, kind, blob) do
def attach_file(struct = %Ecto.Changeset{}, kind, blob) do
cover = apply(struct.data.__struct__, :"#{kind}", [struct.data])
apply(cover.__struct__, :attach, [cover, blob])
end

def attach_file(struct, kind, blob) do
cover = apply(struct.__struct__, :"#{kind}", [struct])
apply(cover.__struct__, :attach, [cover, blob])
end

def fallback_image(url \\ nil) do
RauversionWeb.Router.Helpers.static_path(
RauversionWeb.Endpoint,
Expand Down
65 changes: 65 additions & 0 deletions lib/rauversion/services/dalle.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
defmodule Rauversion.Services.OpenAi do
use Tesla

plug Tesla.Middleware.BaseUrl, "https://api.openai.com/v1/"

plug Tesla.Middleware.JSON

@moduledoc """
client = Rauversion.Services.OpenAi.new
c = Rauversion.OauthCredentials.get_oauth_credential!(1)
Rauversion.Services.OpenAi.images(client, prompt)
"""

def new(token \\ nil) do
token =
case token do
nil ->
Application.get_env(:rauversion, :openai_api_key)

t ->
t
end

Tesla.client([
{Tesla.Middleware.BearerAuth, token: token}
])
end

@doc """
prompt
string Required
A text description of the desired image(s). The maximum length is 1000 characters.
n
integer Optional Defaults to 1
The number of images to generate. Must be between 1 and 10.
size string Optional
Defaults to 1024x1024
The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024.
response_format string
Optional Defaults to url
The format in which the generated images are returned. Must be one of url or b64_json.
user string Optional
A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse. Learn more.
"""
def images(client, prompt) do
options = %{prompt: prompt}

case handle_response(post(client, "/images/generations", options)) do
{:ok, %{"data" => [%{"url" => url}]}} -> {:ok, url}
_ -> {:error, nil}
end
end

defp handle_response({:ok, %{body: %{"error" => error}}}) do
{:error, error}
end

defp handle_response({:ok, %{body: body}}) do
{:ok, body}
end
end
20 changes: 20 additions & 0 deletions lib/rauversion/tracks.ex
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,26 @@ defmodule Rauversion.Tracks do
track.state == "processed"
end

def prompt_cover(prompt) do
client = Rauversion.Services.OpenAi.new()
Rauversion.Services.OpenAi.images(client, prompt)
end

def confirm_prompt(track, url) do
# TODO:
%HTTPoison.Response{body: body} = HTTPoison.get!(url)
tmp_path = "/tmp/image-#{Ecto.UUID.generate()}.png"
:ok = File.write!(tmp_path, body)

file = %{
content_type: "image/png",
filename: "image",
path: tmp_path
}

Rauversion.BlobUtils.attach_file_with_blob(track, "cover", file)
end

def blob_duration_metadata(blob) do
metadata = ActiveStorage.Blob.metadata(blob)

Expand Down
153 changes: 148 additions & 5 deletions lib/rauversion_web/live/track_live/components/edit_form_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,71 @@ defmodule RauversionWeb.TrackLive.EditFormComponent do
# use Phoenix.LiveComponent
use RauversionWeb, :live_component

@impl true
def update(%{action: {:api_call_done, {:ok, url}}}, socket) do
{
:ok,
assign(socket, :prompt_image, url)
|> assign(:loading, false)
}
end

@impl true
def update(assigns, socket) do
{
:ok,
socket
|> assign(assigns)
|> assign(:prompt, nil)
|> assign(:prompt_image, nil)
|> assign(:loading, nil)
}
end

@impl true
def handle_event("set-prompt", %{"value" => value}, socket) do
{:noreply, assign(socket, :prompt, value)}
end

@impl true
def handle_event("redo-prompt", _, socket) do
{:noreply, assign(socket, :prompt_image, nil)}
end

@impl true
def handle_event("generate-prompt", _, socket) do
if connected?(socket) do
view_pid = self()

spawn(fn ->
result = Rauversion.Tracks.prompt_cover(socket.assigns.prompt)
# result = {:ok, "sss"}
# :timer.sleep(2000)

send_update(view_pid, RauversionWeb.TrackLive.EditFormComponent,
id: "track-form-edit-info",
action: {:api_call_done, result}
)
end)
end

{:noreply, assign(socket, :loading, true)}
# {:noreply, assign(socket, :prompt_image, url)}
end

@impl true
def handle_event("confirm-prompt", _, socket) do
Rauversion.Tracks.confirm_prompt(socket.assigns.track, socket.assigns.prompt_image)

{:noreply,
socket
|> put_flash(:info, "Cover updated successfully")
|> push_redirect(to: "/tracks/#{socket.assigns.track.id}")}

# {:noreply, assign(socket, :prompt, value)}
end

@impl true
def render(
%{
uploads: _uploads,
Expand Down Expand Up @@ -31,7 +96,7 @@ defmodule RauversionWeb.TrackLive.EditFormComponent do
<div class="sm:hidden">
<label for="tabs" class="sr-only"><%= gettext "Select a tab" %></label>
<!-- Use an "onChange" listener to redirect the user to the selected tab URL. -->
<select id="tabs" name="tabs" class="block w-full focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 rounded-md">
<select id="tabs" name="tabs" class="block w-full focus:ring-brand-500 focus:border-brand-500 border-gray-300 rounded-md">
<option><%= gettext "Basic Info" %></option>
<option><%= gettext "Metadata" %></option>
Expand All @@ -45,7 +110,7 @@ defmodule RauversionWeb.TrackLive.EditFormComponent do
<div class="hidden sm:block">
<% #= @current_tab %>
<nav class="flex space-x-4" aria-label="Tabs" data-controller-dis="tabs">
<!-- Current: "bg-indigo-100 text-indigo-700", Default: "text-gray-500 hover:text-gray-700 dark:text-gray-300" -->
<!-- Current: "bg-brand-100 text-brand-700", Default: "text-gray-500 hover:text-gray-700 dark:text-gray-300" -->
<a href="#" phx-click="basic-info-tab" class={"#{active_tab_link?(@current_tab, "basic-info-tab")} tab-link px-3 py-2 font-medium text-sm rounded-md"}> <%= gettext "Basic Info" %> </a>
<a href="#" phx-click="metadata-tab" class={"#{active_tab_link?(@current_tab, "metadata-tab")} tab-link px-3 py-2 font-medium text-sm rounded-md"}> <%= gettext "Metadata" %> </a>
<a href="#" phx-click="permissions-tab" class={"#{active_tab_link?(@current_tab, "permissions-tab")} tab-link px-3 py-2 font-medium text-sm rounded-md"} aria-current="page"> <%= gettext "Permissions" %> </a>
Expand Down Expand Up @@ -87,18 +152,18 @@ defmodule RauversionWeb.TrackLive.EditFormComponent do
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
<label for="cover-photo" class="block text-sm font-medium text-gray-700 dark:text-gray-300 sm:mt-px sm:pt-2">
<%= gettext "Cover photo" %>
<%= gettext "Cover photo" %>
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<div class="max-w-lg flex justify-center px-6 pt-5 pb-6 border-2 border-gray-300 border-dashed rounded-md"
phx-drop-target={@uploads.cover.ref}>
<div class="space-y-1 text-center">
<div class="space-y-1 text-center justify-center">
<svg class="mx-auto h-12 w-12 text-gray-400" stroke="currentColor" fill="none" viewBox="0 0 48 48" aria-hidden="true">
<path d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
<div class="flex text-sm text-gray-600 py-3">
<div class="flex text-sm text-gray-600 py-3 justify-center">
<label class="relative cursor-pointer rounded-md font-medium text-brand-600 hover:text-brand-500 focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-brand-500">
<span><%= gettext "Upload a track Cover" %></span>
<.live_file_input upload={@uploads.cover} class="hidden" />
Expand All @@ -125,9 +190,87 @@ defmodule RauversionWeb.TrackLive.EditFormComponent do
<p class="text-xs text-gray-500">
<%= gettext "PNG, JPG, GIF up to 10MB" %>
</p>
<div class="mt-8 sm:w-full sm:max-w-md xl:mt-0 py-4">
<label for={:prompt} class="relative cursor-pointer rounded-md font-medium text-brand-600 hover:text-brand-500 focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-brand-500">
<%= gettext("Or generate the image with AI") %>
</label>
<%= unless @prompt_image do %>
<div class="flex items-center justify-center space-x-3">
<div>
<%= text_input f, :prompt, phx_keyup: "set-prompt", phx_target: @myself,
class: "bg-black w-full rounded-md border-white px-2 py-1 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-brand-700",
placeholder: "Bits on fire",
disabled: @loading %>
</div>
<button
type="button"
phx-click="generate-prompt"
phx-target={@myself}
disabled={@loading}
class="mt-3 flex w-full items-center justify-center rounded-md border border-transparent bg-brand-500 px-1 py-1 text-base font-medium text-white shadow hover:bg-brand-400 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-brand-700 sm:mt-0 sm:ml-3 sm:w-auto sm:flex-shrink-0">
<%= gettext("generate image") %>
</button>
<%= if @loading do %>
<div role="status">
<svg aria-hidden="true" class="mr-2 w-8 h-8 text-gray-200 animate-spin dark:text-gray-600 fill-blue-600" viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z" fill="currentColor"/>
<path d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z" fill="currentFill"/>
</svg>
<span class="sr-only">Loading...</span>
</div>
<% end %>
</div>
<p class="mt-3 text-sm text-brand-200">
<%= gettext("We use DALL-E from Open AI to generate images") %>
<!-- space -->
<a href="https://openai.com/dall-e-2/" target="blank" class="font-medium text-white underline"><%= gettext("read more") %>.</a>
</p>
<% end %>
<%= if @prompt_image do %>
<%= img_tag(@prompt_image,
class: "object-center object-cover group-hover:opacity-75")
%>
<div class="flex space-x-2">
<button
type="button"
phx-click="confirm-prompt"
phx-target={@myself}
disabled={@loading}
class="mt-3 flex w-full items-center justify-center rounded-md border border-transparent bg-brand-500 px-1 py-1 text-base font-medium text-white shadow hover:bg-brand-400 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-brand-700 sm:mt-0 sm:ml-3 sm:w-auto sm:flex-shrink-0">
<%= gettext("Confirm image") %>
</button>
<button
type="button"
phx-click="redo-prompt"
phx-target={@myself}
disabled={@loading}
class="mt-3 flex w-full items-center justify-center rounded-md border border-transparent bg-gray-500 px-1 py-1 text-base font-medium text-white shadow hover:bg-gray-400 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-700 sm:mt-0 sm:ml-3 sm:w-auto sm:flex-shrink-0">
<%= gettext("Redo image") %>
</button>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
<%= if @step.name == "info" and @action == :edit do %>
<.live_component
module={RauversionWeb.TrackLive.EditFormComponent}
id="track-form"
id="track-form-edit-info"
changeset={@changeset}
track={@track}
step={@step}
Expand Down
8 changes: 4 additions & 4 deletions lib/rauversion_web/live/track_live/show.ex
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ defmodule RauversionWeb.TrackLive.Show do

defp metatags(socket, track) do
# "https://chaskiq.ngrok.io"
domain = Application.get_env(:rauversion, :domain )
domain = Application.get_env(:rauversion, :domain)

%{
url: Routes.articles_show_url(socket, :show, track.id),
Expand Down Expand Up @@ -165,8 +165,8 @@ defmodule RauversionWeb.TrackLive.Show do
end

defp oembed_meta(socket, track = %{private: true}) do
Routes.embed_url(socket, :oembed_private_show, Rauversion.Tracks.signed_id(track), %{
format: :json
})
Routes.embed_url(socket, :oembed_private_show, Rauversion.Tracks.signed_id(track), %{
format: :json
})
end
end

0 comments on commit b213068

Please sign in to comment.