styling, require a code for prompts, admin privs, ordering, filtering, jump-to-page
This commit is contained in:
205
lib/diffuser/accounts.ex
Normal file
205
lib/diffuser/accounts.ex
Normal file
@@ -0,0 +1,205 @@
|
||||
defmodule Diffuser.Accounts do
|
||||
@moduledoc """
|
||||
The Accounts context.
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Diffuser.Repo
|
||||
|
||||
alias Diffuser.Accounts.User
|
||||
alias Diffuser.Generator.PromptRequest
|
||||
|
||||
@doc """
|
||||
Returns the list of users.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_users()
|
||||
[%User{}, ...]
|
||||
|
||||
"""
|
||||
def list_users do
|
||||
Repo.all(User)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single user.
|
||||
|
||||
Raises `Ecto.NoResultsError` if the User does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_user!(123)
|
||||
%User{}
|
||||
|
||||
iex> get_user!(456)
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
def get_user!(id), do: Repo.get!(User, id) |> Repo.preload(votes: [:prompt_request])
|
||||
|
||||
@doc """
|
||||
Creates a user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_user(%{field: value})
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> create_user(%{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_user(attrs \\ %{}) do
|
||||
%User{}
|
||||
|> User.changeset(attrs)
|
||||
|> Repo.insert()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> update_user(user, %{field: new_value})
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> update_user(user, %{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def update_user(%User{} = user, attrs) do
|
||||
user
|
||||
|> User.changeset(attrs)
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> delete_user(user)
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> delete_user(user)
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def delete_user(%User{} = user) do
|
||||
Repo.delete(user)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for tracking user changes.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_user(user)
|
||||
%Ecto.Changeset{data: %User{}}
|
||||
|
||||
"""
|
||||
def change_user(%User{} = user, attrs \\ %{}) do
|
||||
User.changeset(user, attrs)
|
||||
end
|
||||
|
||||
alias Diffuser.Accounts.Vote
|
||||
|
||||
@doc """
|
||||
Returns the list of votes.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_votes()
|
||||
[%Vote{}, ...]
|
||||
|
||||
"""
|
||||
def list_votes do
|
||||
Repo.all(Vote)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single vote.
|
||||
|
||||
Raises `Ecto.NoResultsError` if the Vote does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_vote!(123)
|
||||
%Vote{}
|
||||
|
||||
iex> get_vote!(456)
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
def get_vote!(id), do: Repo.get!(Vote, id)
|
||||
|
||||
@doc """
|
||||
Creates a vote.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_vote(%{field: value})
|
||||
{:ok, %Vote{}}
|
||||
|
||||
iex> create_vote(%{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_vote(%{user: user} = attrs) do
|
||||
%Vote{}
|
||||
|> Vote.changeset(attrs)
|
||||
|> Ecto.Changeset.put_assoc(:user, user)
|
||||
|> Repo.insert()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a vote.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> update_vote(vote, %{field: new_value})
|
||||
{:ok, %Vote{}}
|
||||
|
||||
iex> update_vote(vote, %{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def update_vote(%Vote{} = vote, attrs) do
|
||||
vote
|
||||
|> Vote.changeset(attrs)
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a vote.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> delete_vote(vote)
|
||||
{:ok, %Vote{}}
|
||||
|
||||
iex> delete_vote(vote)
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def delete_vote(%Vote{} = vote) do
|
||||
Repo.delete(vote)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for tracking vote changes.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_vote(vote)
|
||||
%Ecto.Changeset{data: %Vote{}}
|
||||
|
||||
"""
|
||||
def change_vote(%Vote{} = vote, attrs \\ %{}) do
|
||||
Vote.changeset(vote, attrs)
|
||||
end
|
||||
|
||||
def upvote(user, %PromptRequest{id: pr}),
|
||||
do: create_vote(%{prompt_request_id: pr, user: user})
|
||||
end
|
25
lib/diffuser/accounts/user.ex
Normal file
25
lib/diffuser/accounts/user.ex
Normal file
@@ -0,0 +1,25 @@
|
||||
defmodule Diffuser.Accounts.User do
|
||||
use Diffuser.Schema
|
||||
import Ecto.Changeset
|
||||
alias Diffuser.Accounts.Vote
|
||||
alias Diffuser.Generator.PromptRequest
|
||||
|
||||
schema "users" do
|
||||
field :ip_address, :string
|
||||
field :username, :string
|
||||
field :code, :string
|
||||
|
||||
has_many :votes, Vote, on_delete: :delete_all
|
||||
has_many :prompt_requests, PromptRequest, on_delete: :delete_all
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@doc false
|
||||
def changeset(user, attrs) do
|
||||
user
|
||||
|> cast(attrs, [:ip_address, :username, :code])
|
||||
|> cast_assoc(:votes)
|
||||
|> cast_assoc(:prompt_requests)
|
||||
end
|
||||
end
|
20
lib/diffuser/accounts/vote.ex
Normal file
20
lib/diffuser/accounts/vote.ex
Normal file
@@ -0,0 +1,20 @@
|
||||
defmodule Diffuser.Accounts.Vote do
|
||||
use Diffuser.Schema
|
||||
import Ecto.Changeset
|
||||
alias Diffuser.Generator.PromptRequest
|
||||
alias Diffuser.Accounts.User
|
||||
|
||||
schema "votes" do
|
||||
belongs_to :prompt_request, PromptRequest
|
||||
belongs_to :user, User
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@doc false
|
||||
def changeset(vote, attrs) do
|
||||
vote
|
||||
|> cast(attrs, [:prompt_request_id, :user_id])
|
||||
|> validate_required([])
|
||||
end
|
||||
end
|
@@ -36,7 +36,9 @@ defmodule Diffuser.Generator do
|
||||
|
||||
"""
|
||||
def get_prompt_request!(id),
|
||||
do: Repo.one!(from pr in PromptRequest, where: pr.id == ^id) |> Repo.preload(:images)
|
||||
do:
|
||||
Repo.one!(from pr in PromptRequest, where: pr.id == ^id)
|
||||
|> Repo.preload([:votes, :images, :user])
|
||||
|
||||
@doc """
|
||||
Creates a prompt_request.
|
||||
@@ -50,9 +52,18 @@ defmodule Diffuser.Generator do
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_prompt_request(attrs \\ %{}) do
|
||||
def create_prompt_request(%{"user" => user} = attrs) do
|
||||
user = Diffuser.Accounts.get_user!(user)
|
||||
code = Map.get(user, :code, nil)
|
||||
|
||||
attrs =
|
||||
if is_nil(code),
|
||||
do: attrs |> Map.put("code", "garbage"),
|
||||
else: attrs |> Map.put("code", code)
|
||||
|
||||
%PromptRequest{}
|
||||
|> PromptRequest.changeset(attrs)
|
||||
|> Ecto.Changeset.put_assoc(:user, user)
|
||||
|> Repo.insert()
|
||||
end
|
||||
|
||||
@@ -74,6 +85,9 @@ defmodule Diffuser.Generator do
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
def update_prompt_request(id, attrs),
|
||||
do: get_prompt_request!(id) |> update_prompt_request(attrs)
|
||||
|
||||
@doc """
|
||||
Deletes a prompt_request.
|
||||
|
||||
@@ -123,9 +137,14 @@ defmodule Diffuser.Generator do
|
||||
end)
|
||||
end
|
||||
|
||||
def paginate_prompt_requests(params) do
|
||||
PromptRequest
|
||||
|> preload(:images)
|
||||
def paginate_prompt_requests(query \\ PromptRequest, params) do
|
||||
search_query = Map.get(params, :query, nil)
|
||||
order_by_query = Map.get(params, :order_by, nil)
|
||||
|
||||
query
|
||||
|> PromptRequest.search_by_prompt_or_user(search_query)
|
||||
|> PromptRequest.order_by(order_by_query)
|
||||
|> preload([:votes, :user, :images])
|
||||
|> Repo.paginate(params)
|
||||
end
|
||||
end
|
||||
|
@@ -1,17 +1,26 @@
|
||||
defmodule Diffuser.Generator.PromptRequest do
|
||||
use Ecto.Schema
|
||||
use Diffuser.Schema
|
||||
use Waffle.Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
import Ecto.Query
|
||||
alias Diffuser.Generator.PromptRequestResult
|
||||
alias Diffuser.Accounts.{User, Vote}
|
||||
|
||||
@valid_codes Application.get_env(:diffuser, :valid_codes, [])
|
||||
|
||||
@primary_key {:id, Ecto.UUID, autogenerate: true}
|
||||
schema "prompt_requests" do
|
||||
field :prompt, :string
|
||||
field :status, :string, default: "queued"
|
||||
field :steps, :integer
|
||||
field :guidance_scale, :float
|
||||
field :steps, :integer, default: 32
|
||||
field :completed_steps, :integer, default: 0
|
||||
field :guidance_scale, :float, default: 7.5
|
||||
field :began_at, :utc_datetime
|
||||
field :ended_at, :utc_datetime
|
||||
field :code, :string
|
||||
|
||||
has_many :images, PromptRequestResult, on_delete: :delete_all
|
||||
has_many :votes, Vote, on_delete: :delete_all
|
||||
belongs_to :user, User
|
||||
|
||||
timestamps()
|
||||
end
|
||||
@@ -19,7 +28,63 @@ defmodule Diffuser.Generator.PromptRequest do
|
||||
@doc false
|
||||
def changeset(prompt_request, attrs) do
|
||||
prompt_request
|
||||
|> cast(attrs, [:prompt, :status, :steps, :guidance_scale])
|
||||
|> cast(attrs, [
|
||||
:prompt,
|
||||
:status,
|
||||
:steps,
|
||||
:guidance_scale,
|
||||
:completed_steps,
|
||||
:began_at,
|
||||
:ended_at,
|
||||
:code
|
||||
])
|
||||
|> validate_number(:steps, less_than_or_equal_to: 60)
|
||||
|> validate_code()
|
||||
|> validate_required([:prompt])
|
||||
end
|
||||
|
||||
defp validate_code(changeset) do
|
||||
validate_change(changeset, :code, fn :code, code ->
|
||||
cond do
|
||||
@valid_codes
|
||||
|> Enum.any?(fn {_name, valid_code} ->
|
||||
valid_code == code
|
||||
end) ->
|
||||
[]
|
||||
|
||||
true ->
|
||||
[code: "Code is invalid."]
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
def search_by_prompt_or_user(query, nil), do: query
|
||||
|
||||
def search_by_prompt_or_user(query, search_query) do
|
||||
from p in query,
|
||||
left_join: u in User,
|
||||
on: u.id == p.user_id,
|
||||
where: ilike(p.prompt, ^"%#{search_query}%")
|
||||
end
|
||||
|
||||
def order_by(query, nil) do
|
||||
from p in query,
|
||||
order_by: [desc: p.inserted_at]
|
||||
end
|
||||
|
||||
def order_by(query, "desc") do
|
||||
from p in query,
|
||||
join: v in Vote,
|
||||
on: v.prompt_request_id == p.id,
|
||||
group_by: p.id,
|
||||
order_by: [desc: count(v.id)]
|
||||
end
|
||||
|
||||
def order_by(query, "asc") do
|
||||
from p in query,
|
||||
left_join: v in Vote,
|
||||
on: v.prompt_request_id == p.id,
|
||||
group_by: p.id,
|
||||
order_by: [asc: count(v.id)]
|
||||
end
|
||||
end
|
||||
|
@@ -1,13 +1,12 @@
|
||||
defmodule Diffuser.Generator.PromptRequestResult do
|
||||
use Ecto.Schema
|
||||
use Diffuser.Schema
|
||||
use Waffle.Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Diffuser.Generator.PromptRequest
|
||||
|
||||
@primary_key {:id, Ecto.UUID, autogenerate: true}
|
||||
schema "prompt_request_results" do
|
||||
field :image, Diffuser.Uploaders.Image.Type
|
||||
belongs_to :prompt_request, PromptRequest, type: :binary_id
|
||||
belongs_to :prompt_request, PromptRequest
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
@@ -5,8 +5,6 @@ defmodule Diffuser.Generator.PromptRequestWorker do
|
||||
alias Diffuser.Repo
|
||||
|
||||
@path [:code.priv_dir(:diffuser), "python"] |> Path.join()
|
||||
@steps 10
|
||||
@guidance_scale 7.5
|
||||
|
||||
def start(%PromptRequest{} = prompt_request) do
|
||||
with {:ok, active_prompt} <-
|
||||
@@ -26,24 +24,38 @@ defmodule Diffuser.Generator.PromptRequestWorker do
|
||||
end
|
||||
end
|
||||
|
||||
defp update_and_broadcast_progress(%PromptRequest{id: id} = prompt_request, new_status) do
|
||||
{:ok, new_prompt} =
|
||||
Generator.update_prompt_request(prompt_request, %{
|
||||
status: new_status,
|
||||
steps: @steps,
|
||||
guidance_scale: @guidance_scale
|
||||
defp update_and_broadcast_progress(prompt_request, "in_progress"),
|
||||
do:
|
||||
update_and_broadcast_progress(prompt_request, %{
|
||||
status: "in_progress",
|
||||
began_at: NaiveDateTime.utc_now()
|
||||
})
|
||||
|
||||
defp update_and_broadcast_progress(prompt_request, "finished"),
|
||||
do:
|
||||
update_and_broadcast_progress(prompt_request, %{
|
||||
status: "finished",
|
||||
ended_at: NaiveDateTime.utc_now()
|
||||
})
|
||||
|
||||
defp update_and_broadcast_progress(%PromptRequest{id: id} = prompt_request, attrs) do
|
||||
{:ok, new_prompt} = Generator.update_prompt_request(prompt_request, attrs)
|
||||
|
||||
:ok = Endpoint.broadcast("request:#{id}", "request", %{prompt_request: new_prompt})
|
||||
|
||||
{:ok, new_prompt}
|
||||
end
|
||||
|
||||
defp call_python(_module, _func, %{id: prompt_id, prompt: prompt}) do
|
||||
defp call_python(_module, _func, %PromptRequest{
|
||||
id: prompt_id,
|
||||
prompt: prompt,
|
||||
steps: steps,
|
||||
guidance_scale: guidance_scale
|
||||
}) do
|
||||
port =
|
||||
Port.open(
|
||||
{:spawn,
|
||||
~s(python #{@path}/stable_diffusion.py --prompt "#{prompt}" --output "#{@path}/#{prompt_id}.png" --num-inference-steps #{@steps})},
|
||||
~s(python #{@path}/stable_diffusion.py --prompt "#{prompt}" --output "#{@path}/#{prompt_id}.png" --num-inference-steps #{steps} --guidance-scale #{guidance_scale})},
|
||||
[:binary]
|
||||
)
|
||||
|
||||
@@ -56,11 +68,18 @@ defmodule Diffuser.Generator.PromptRequestWorker do
|
||||
{:ok, msg}
|
||||
|
||||
{^port, {:data, ":step" <> step}} ->
|
||||
Endpoint.broadcast("request:#{prompt_id}", "progress", step)
|
||||
{:ok, prompt_request} =
|
||||
Generator.update_prompt_request(prompt_id, %{completed_steps: step})
|
||||
|
||||
Endpoint.broadcast(
|
||||
"request:#{prompt_id}",
|
||||
"progress",
|
||||
%{prompt_request: prompt_request |> Repo.preload(:images)}
|
||||
)
|
||||
|
||||
python_loop(port, prompt_id)
|
||||
|
||||
{^port, result} ->
|
||||
IO.inspect(result, label: "RESULT")
|
||||
{^port, _result} ->
|
||||
python_loop(port, prompt_id)
|
||||
end
|
||||
end
|
||||
|
@@ -3,5 +3,5 @@ defmodule Diffuser.Repo do
|
||||
otp_app: :diffuser,
|
||||
adapter: Ecto.Adapters.Postgres
|
||||
|
||||
use Scrivener, page_size: 1
|
||||
use Scrivener, page_size: 12
|
||||
end
|
||||
|
9
lib/diffuser/schema.ex
Normal file
9
lib/diffuser/schema.ex
Normal file
@@ -0,0 +1,9 @@
|
||||
defmodule Diffuser.Schema do
|
||||
defmacro __using__(_) do
|
||||
quote do
|
||||
use Ecto.Schema
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@foreign_key_type :binary_id
|
||||
end
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user