diff --git a/examples/phoenix/image_classification.exs b/examples/phoenix/image_classification.exs index d77f0c7c..f0374f42 100644 --- a/examples/phoenix/image_classification.exs +++ b/examples/phoenix/image_classification.exs @@ -1,17 +1,5 @@ -Application.put_env(:sample, PhoenixDemo.Endpoint, - http: [ip: {127, 0, 0, 1}, port: 8080], - server: true, - live_view: [signing_salt: "bumblebee"], - secret_key_base: String.duplicate("b", 64), - pubsub_server: PhoenixDemo.PubSub -) - Mix.install([ - {:plug_cowboy, "~> 2.6"}, - {:jason, "~> 1.4"}, - {:phoenix, "1.7.10"}, - {:phoenix_live_view, "0.20.1"}, - # Bumblebee and friends + {:phoenix_playground, "~> 0.1.7"}, {:bumblebee, "~> 0.6.0"}, {:nx, "~> 0.9.0"}, {:exla, "~> 0.9.0"} @@ -19,201 +7,178 @@ Mix.install([ Application.put_env(:nx, :default_backend, EXLA.Backend) -defmodule PhoenixDemo.Layouts do - use Phoenix.Component +defmodule DemoLive do + use Phoenix.LiveView + + @impl true + def mount(_params, _session, socket) do + {:ok, + socket + |> assign(label: nil) + |> allow_upload(:image, accept: :any, progress: &handle_progress/3, auto_upload: true)} + end - def render("live.html", assigns) do + @impl true + def render(assigns) do ~H""" - - - - - <%= @inner_content %> - """ - end -end + canvas.width = scaledWidth; + canvas.height = scaledHeight; -defmodule PhoenixDemo.ErrorView do - def render(_, _), do: "error" -end + ctx.drawImage(imgEl, 0, 0, width, height, 0, 0, scaledWidth, scaledHeight); -defmodule PhoenixDemo.SampleLive do - use Phoenix.LiveView, layout: {PhoenixDemo.Layouts, :live} + return canvas; + }, - @impl true - def mount(_params, _session, socket) do - {:ok, - socket - |> assign(label: nil) - |> allow_upload(:image, accept: :any, progress: &handle_progress/3, auto_upload: true)} - end + canvasToBlob(canvas) { + const imageData = canvas + .getContext("2d") + .getImageData(0, 0, canvas.width, canvas.height); - @impl true - def render(assigns) do - ~H""" -
-
-
- <.image_input id="image" upload={@uploads.image} height={224} width={224} /> -
-
- Label: - <.async_result :let={label} assign={@label} :if={@label}> - <:loading> - <.spinner /> - - <:failed :let={_reason}> - Oops, something went wrong! - - <%= label %> - -
-
+ const buffer = this.imageDataToRGBBuffer(imageData); + + const meta = new ArrayBuffer(8); + const view = new DataView(meta); + view.setUint32(0, canvas.height, false); + view.setUint32(4, canvas.width, false); + + return new Blob([meta, buffer], { type: "application/octet-stream" }); + }, + + imageDataToRGBBuffer(imageData) { + const pixelCount = imageData.width * imageData.height; + const bytes = new Uint8ClampedArray(pixelCount * 3); + + for (let i = 0; i < pixelCount; i++) { + bytes[i * 3] = imageData.data[i * 4]; + bytes[i * 3 + 1] = imageData.data[i * 4 + 1]; + bytes[i * 3 + 2] = imageData.data[i * 4 + 2]; + } + + return bytes.buffer; + }, + }; +
""" end @@ -276,7 +241,7 @@ defmodule PhoenixDemo.SampleLive do # Discard previous label so we show the loading state once more |> assign(:label, nil) |> assign_async(:label, fn -> - output = Nx.Serving.batched_run(PhoenixDemo.Serving, image) + output = Nx.Serving.batched_run(Demo.Serving, image) %{predictions: [%{label: label}]} = output {:ok, %{label: label}} end) @@ -299,29 +264,6 @@ defmodule PhoenixDemo.SampleLive do end end -defmodule PhoenixDemo.Router do - use Phoenix.Router - - import Phoenix.LiveView.Router - - pipeline :browser do - plug(:accepts, ["html"]) - end - - scope "/", PhoenixDemo do - pipe_through(:browser) - - live("/", SampleLive, :index) - end -end - -defmodule PhoenixDemo.Endpoint do - use Phoenix.Endpoint, otp_app: :sample - - socket("/live", Phoenix.LiveView.Socket) - plug(PhoenixDemo.Router) -end - # Application startup {:ok, model_info} = Bumblebee.load_model({:hf, "microsoft/resnet-50"}) @@ -331,17 +273,12 @@ serving = Bumblebee.Vision.image_classification(model_info, featurizer, top_k: 1, compile: [batch_size: 4], - defn_options: [compiler: EXLA] + defn_options: [ + compiler: EXLA, + cache: Path.join(System.tmp_dir!(), "bumblebee_examples/image_classification") + ] ) -{:ok, _} = - Supervisor.start_link( - [ - {Phoenix.PubSub, name: PhoenixDemo.PubSub}, - {Nx.Serving, serving: serving, name: PhoenixDemo.Serving, batch_timeout: 100}, - PhoenixDemo.Endpoint - ], - strategy: :one_for_one - ) +Nx.Serving.start_link(serving: serving, name: Demo.Serving, batch_timeout: 100) -Process.sleep(:infinity) +PhoenixPlayground.start(live: DemoLive, port: 8080) diff --git a/examples/phoenix/speech_to_text.exs b/examples/phoenix/speech_to_text.exs index 7db93fee..f51bdb30 100644 --- a/examples/phoenix/speech_to_text.exs +++ b/examples/phoenix/speech_to_text.exs @@ -1,17 +1,5 @@ -Application.put_env(:sample, PhoenixDemo.Endpoint, - http: [ip: {127, 0, 0, 1}, port: 8080], - server: true, - live_view: [signing_salt: "bumblebee"], - secret_key_base: String.duplicate("b", 64), - pubsub_server: PhoenixDemo.PubSub -) - Mix.install([ - {:plug_cowboy, "~> 2.6"}, - {:jason, "~> 1.4"}, - {:phoenix, "1.7.10"}, - {:phoenix_live_view, "0.20.1"}, - # Bumblebee and friends + {:phoenix_playground, "~> 0.1.7"}, {:bumblebee, "~> 0.6.0"}, {:nx, "~> 0.9.0"}, {:exla, "~> 0.9.0"} @@ -19,21 +7,62 @@ Mix.install([ Application.put_env(:nx, :default_backend, EXLA.Backend) -defmodule PhoenixDemo.Layouts do - use Phoenix.Component +defmodule DemoLive do + use Phoenix.LiveView - def render("live.html", assigns) do + @impl true + def mount(_params, _session, socket) do + {:ok, + socket + |> assign(transcription: nil) + |> allow_upload(:audio, accept: :any, progress: &handle_progress/3, auto_upload: true)} + end + + @impl true + def render(assigns) do ~H""" - - + +
+
+
+

Press and hold

+
+ + + + + +
+
Transcription:
+ <.async_result :let={transcription} :if={@transcription} assign={@transcription}> + <:loading> + <.spinner /> + + <:failed :let={_reason}> + Oops, something went wrong! + + <%= transcription %> + +
+
+
+ - - <%= @inner_content %> - """ - end -end - -defmodule PhoenixDemo.ErrorView do - def render(_, _), do: "error" -end - -defmodule PhoenixDemo.SampleLive do - use Phoenix.LiveView, layout: {PhoenixDemo.Layouts, :live} - - @impl true - def mount(_params, _session, socket) do - {:ok, - socket - |> assign(transcription: nil) - |> allow_upload(:audio, accept: :any, progress: &handle_progress/3, auto_upload: true)} - end - - @impl true - def render(assigns) do - ~H""" -
-
-
-

Press and hold

-
- - - - - -
-
Transcription:
- <.async_result :let={transcription} assign={@transcription} :if={@transcription}> - <:loading> - <.spinner /> - - <:failed :let={_reason}> - Oops, something went wrong! - - <%= transcription %> - -
-
-
""" end @@ -274,7 +239,7 @@ defmodule PhoenixDemo.SampleLive do # Discard previous transcription so we show the loading state once more |> assign(:transcription, nil) |> assign_async(:transcription, fn -> - output = Nx.Serving.batched_run(PhoenixDemo.Serving, audio) + output = Nx.Serving.batched_run(Demo.Serving, audio) transcription = output.chunks |> Enum.map_join(& &1.text) |> String.trim() {:ok, %{transcription: transcription}} end) @@ -293,29 +258,6 @@ defmodule PhoenixDemo.SampleLive do end end -defmodule PhoenixDemo.Router do - use Phoenix.Router - - import Phoenix.LiveView.Router - - pipeline :browser do - plug(:accepts, ["html"]) - end - - scope "/", PhoenixDemo do - pipe_through(:browser) - - live("/", SampleLive, :index) - end -end - -defmodule PhoenixDemo.Endpoint do - use Phoenix.Endpoint, otp_app: :sample - - socket("/live", Phoenix.LiveView.Socket) - plug(PhoenixDemo.Router) -end - # Application startup {:ok, model_info} = Bumblebee.load_model({:hf, "openai/whisper-tiny"}) @@ -326,17 +268,12 @@ end serving = Bumblebee.Audio.speech_to_text_whisper(model_info, featurizer, tokenizer, generation_config, compile: [batch_size: 4], - defn_options: [compiler: EXLA] + defn_options: [ + compiler: EXLA, + cache: Path.join(System.tmp_dir!(), "bumblebee_examples/speech_to_text") + ] ) -{:ok, _} = - Supervisor.start_link( - [ - {Phoenix.PubSub, name: PhoenixDemo.PubSub}, - {Nx.Serving, serving: serving, name: PhoenixDemo.Serving, batch_timeout: 100}, - PhoenixDemo.Endpoint - ], - strategy: :one_for_one - ) +Nx.Serving.start_link(serving: serving, name: Demo.Serving, batch_timeout: 100) -Process.sleep(:infinity) +PhoenixPlayground.start(live: DemoLive, port: 8080) diff --git a/examples/phoenix/text_classification.exs b/examples/phoenix/text_classification.exs index 63436959..77b2d135 100644 --- a/examples/phoenix/text_classification.exs +++ b/examples/phoenix/text_classification.exs @@ -1,16 +1,5 @@ -Application.put_env(:sample, PhoenixDemo.Endpoint, - http: [ip: {127, 0, 0, 1}, port: 8080], - server: true, - live_view: [signing_salt: "bumblebee"], - secret_key_base: String.duplicate("b", 64) -) - Mix.install([ - {:plug_cowboy, "~> 2.6"}, - {:jason, "~> 1.4"}, - {:phoenix, "1.7.10"}, - {:phoenix_live_view, "0.20.1"}, - # Bumblebee and friends + {:phoenix_playground, "~> 0.1.7"}, {:bumblebee, "~> 0.6.0"}, {:nx, "~> 0.9.0"}, {:exla, "~> 0.9.0"} @@ -18,34 +7,8 @@ Mix.install([ Application.put_env(:nx, :default_backend, EXLA.Backend) -defmodule PhoenixDemo.Layouts do - use Phoenix.Component - - def render("live.html", assigns) do - ~H""" - - - - - <%= @inner_content %> - """ - end -end - -defmodule PhoenixDemo.ErrorView do - def render(_, _), do: "error" -end - -defmodule PhoenixDemo.SampleLive do - use Phoenix.LiveView, layout: {PhoenixDemo.Layouts, :live} +defmodule DemoLive do + use Phoenix.LiveView @impl true def mount(_params, _session, socket) do @@ -55,6 +18,9 @@ defmodule PhoenixDemo.SampleLive do @impl true def render(assigns) do ~H""" + +
@@ -74,7 +40,7 @@ defmodule PhoenixDemo.SampleLive do
Emotion: - <.async_result :let={label} assign={@label} :if={@label}> + <.async_result :let={label} :if={@label} assign={@label}> <:loading> <.spinner /> @@ -117,7 +83,7 @@ defmodule PhoenixDemo.SampleLive do # Discard previous label so we show the loading state once more |> assign(:label, nil) |> assign_async(:label, fn -> - output = Nx.Serving.batched_run(PhoenixDemo.Serving, text) + output = Nx.Serving.batched_run(Demo.Serving, text) %{predictions: [%{label: label}]} = output {:ok, %{label: label}} end) @@ -126,29 +92,6 @@ defmodule PhoenixDemo.SampleLive do end end -defmodule PhoenixDemo.Router do - use Phoenix.Router - - import Phoenix.LiveView.Router - - pipeline :browser do - plug(:accepts, ["html"]) - end - - scope "/", PhoenixDemo do - pipe_through(:browser) - - live("/", SampleLive, :index) - end -end - -defmodule PhoenixDemo.Endpoint do - use Phoenix.Endpoint, otp_app: :sample - - socket("/live", Phoenix.LiveView.Socket) - plug(PhoenixDemo.Router) -end - # Application startup {:ok, model_info} = Bumblebee.load_model({:hf, "finiteautomata/bertweet-base-emotion-analysis"}) @@ -158,16 +101,12 @@ serving = Bumblebee.Text.text_classification(model_info, tokenizer, top_k: 1, compile: [batch_size: 4, sequence_length: 100], - defn_options: [compiler: EXLA] + defn_options: [ + compiler: EXLA, + cache: Path.join(System.tmp_dir!(), "bumblebee_examples/text_classification") + ] ) -{:ok, _} = - Supervisor.start_link( - [ - {Nx.Serving, serving: serving, name: PhoenixDemo.Serving, batch_timeout: 100}, - PhoenixDemo.Endpoint - ], - strategy: :one_for_one - ) +Nx.Serving.start_link(serving: serving, name: Demo.Serving, batch_timeout: 100) -Process.sleep(:infinity) +PhoenixPlayground.start(live: DemoLive, port: 8080)