From b13de7b574676c6b49bb415c0d1a85967f10809a Mon Sep 17 00:00:00 2001 From: Neven DREAN Date: Wed, 15 Nov 2023 13:44:06 +0100 Subject: [PATCH 1/3] example --- .bumblebee/README.md | 5 -- lib/app/application.ex | 16 +---- lib/app_web/live/page_live.ex | 100 ++++++++++++++++++++------- lib/app_web/live/page_live.html.heex | 73 ++++++++++++------- mix.exs | 8 ++- mix.lock | 11 ++- 6 files changed, 140 insertions(+), 73 deletions(-) delete mode 100644 .bumblebee/README.md diff --git a/.bumblebee/README.md b/.bumblebee/README.md deleted file mode 100644 index 7942753..0000000 --- a/.bumblebee/README.md +++ /dev/null @@ -1,5 +0,0 @@ -This is a cache folder for `Bumblebee` to download the models into and cache them, -to void unnecessary re-downloads of the same model. - -Check https://github.com/elixir-nx/bumblebee/tree/main/examples/phoenix -for more information. \ No newline at end of file diff --git a/lib/app/application.ex b/lib/app/application.ex index 7b66033..f023fde 100644 --- a/lib/app/application.ex +++ b/lib/app/application.ex @@ -29,18 +29,6 @@ defmodule App.Application do end def serving do - - # BLIP ----- - # {:ok, model_info} = Bumblebee.load_model({:hf, "Salesforce/blip-image-captioning-base"}) - # {:ok, featurizer} = Bumblebee.load_featurizer({:hf, "Salesforce/blip-image-captioning-base"}) - # {:ok, tokenizer} = Bumblebee.load_tokenizer({:hf, "Salesforce/blip-image-captioning-base"}) - # {:ok, generation_config} = Bumblebee.load_generation_config({:hf, "Salesforce/blip-image-captioning-base"}) -# - # Bumblebee.Vision.image_to_text(model_info, featurizer, tokenizer, generation_config, - # compile: [batch_size: 10], - # defn_options: [compiler: EXLA] - # ) - # ResNet-50 ----- {:ok, model_info} = Bumblebee.load_model({:hf, "microsoft/resnet-50"}) {:ok, featurizer} = Bumblebee.load_featurizer({:hf, "microsoft/resnet-50"}) @@ -49,9 +37,9 @@ defmodule App.Application do top_k: 1, compile: [batch_size: 10], defn_options: [compiler: EXLA], - preallocate_params: true # needed to run on `Fly.io` + # needed to run on `Fly.io` + preallocate_params: true ) - end # Tell Phoenix to update the endpoint configuration diff --git a/lib/app_web/live/page_live.ex b/lib/app_web/live/page_live.ex index 54aae2c..dc6a1bf 100644 --- a/lib/app_web/live/page_live.ex +++ b/lib/app_web/live/page_live.ex @@ -2,11 +2,25 @@ defmodule AppWeb.PageLive do use AppWeb, :live_view alias Vix.Vips.Image, as: Vimage + @unsplashes [ + "https://source.unsplash.com/_CFv3bntQlQ", + "https://source.unsplash.com/r1SwcagHVG0" + ] + @impl true def mount(_params, _session, socket) do + Process.send_after(self(), :populate_list, 3_000) + {:ok, socket - |> assign(label: nil, running: false, task_ref: nil, image_preview_base64: nil) + |> assign( + label: nil, + running: false, + task_ref: nil, + image_preview_base64: nil, + display_list?: false, + displayed_list: [] + ) |> allow_upload(:image_list, accept: ~w(image/*), auto_upload: true, @@ -24,26 +38,31 @@ defmodule AppWeb.PageLive do def handle_progress(:image_list, entry, socket) do if entry.done? do - # Consume the entry and get the tensor to feed to classifier - %{tensor: tensor, file_binary: file_binary} = consume_uploaded_entry(socket, entry, fn %{} = meta -> - file_binary = File.read!(meta.path) + %{tensor: tensor, file_binary: file_binary} = + consume_uploaded_entry(socket, entry, fn %{} = meta -> + file_binary = File.read!(meta.path) - # Get image and resize - # This is dependant on the resolution of the model's dataset. - # In our case, we want the width to be closer to 640, whilst maintaining aspect ratio. - width = 640 - {:ok, thumbnail_vimage} = Vix.Vips.Operation.thumbnail(meta.path, width, size: :VIPS_SIZE_DOWN) + # Get image and resize + # This is dependant on the resolution of the model's dataset. + # In our case, we want the width to be closer to 640, whilst maintaining aspect ratio. + width = 640 - # Pre-process it - {:ok, tensor} = pre_process_image(thumbnail_vimage) + {:ok, thumbnail_vimage} = + Vix.Vips.Operation.thumbnail(meta.path, width, size: :VIPS_SIZE_DOWN) - # Return it - {:ok, %{tensor: tensor, file_binary: file_binary}} - end) + # Pre-process it + {:ok, tensor} = pre_process_image(thumbnail_vimage) + + # Return it + {:ok, %{tensor: tensor, file_binary: file_binary}} + end) # Create an async task to classify the image - task = Task.Supervisor.async(App.TaskSupervisor, fn -> Nx.Serving.batched_run(ImageClassifier, tensor) end) + task = + Task.Supervisor.async(App.TaskSupervisor, fn -> + Nx.Serving.batched_run(ImageClassifier, tensor) + end) # Encode the image to base64 base64 = "data:image/png;base64, " <> Base.encode64(file_binary) @@ -56,29 +75,62 @@ defmodule AppWeb.PageLive do end @impl true - def handle_info({ref, result}, %{assigns: %{task_ref: ref}} = socket) do + def handle_info({ref, result}, %{assigns: assigns} = socket) do # This is called everytime an Async Task is created. # We flush it here. Process.demonitor(ref, [:flush]) # And then destructure the result from the classifier. # %{results: [%{text: label}]} = result # BLIP - %{predictions: [%{label: label}]} = result # ResNet-50 + # ResNet-50 + %{predictions: [%{label: label}]} = result + + cond do + Map.get(assigns, :task_ref) == ref -> + {:noreply, assign(socket, label: label, running: false)} + + img = Map.get(assigns, :pre_list_tasks) |> Enum.find(&(&1.ref == ref)) -> + {:noreply, + assign(socket, + displayed_list: [%{url: img.url, label: label} | assigns.displayed_list], + running: false, + display_list?: true + )} + + true -> + nil + {:noreply, socket} + end + end + def handle_info(:populate_list, socket) do + tasks = @unsplashes |> Enum.map(&handle_image/1) - # Update the socket assigns with result and stopping spinner. - {:noreply, assign(socket, label: label, running: false)} + {:noreply, assign(socket, pre_list_tasks: tasks)} + end + + def handle_image(url) do + {:ok, img} = + Req.get!(url).body + |> Vix.Vips.Image.new_from_buffer() + + {:ok, t_img} = pre_process_image(img) + + Task.Supervisor.async(App.TaskSupervisor, fn -> + Nx.Serving.batched_run(ImageClassifier, t_img) + end) + |> Map.merge(%{url: url}) end def error_to_string(:too_large), do: "Image too large. Upload a smaller image up to 10MB." defp pre_process_image(%Vimage{} = image) do - # If the image has an alpha channel, flatten it: - {:ok, flattened_image} = case Vix.Vips.Image.has_alpha?(image) do - true -> Vix.Vips.Operation.flatten(image) - false -> {:ok, image} - end + {:ok, flattened_image} = + case Vix.Vips.Image.has_alpha?(image) do + true -> Vix.Vips.Operation.flatten(image) + false -> {:ok, image} + end # Convert the image to sRGB colourspace ---------------- {:ok, srgb_image} = Vix.Vips.Operation.colourspace(flattened_image, :VIPS_INTERPRETATION_sRGB) diff --git a/lib/app_web/live/page_live.html.heex b/lib/app_web/live/page_live.html.heex index da9beed..dd5f9c2 100644 --- a/lib/app_web/live/page_live.html.heex +++ b/lib/app_web/live/page_live.html.heex @@ -5,10 +5,18 @@

Image Classification

- Do simple classification with this LiveView - demo, powered by Bumblebee. + Do simple classification with this + + LiveView + + demo, powered by Bumblebee.

-
@@ -22,19 +30,30 @@
<% else %> -
-
- - <%= for entry <- @uploads.image_list.entries do %> -
+
<%= for err <- upload_errors(@uploads.image_list, entry) do %>
@@ -78,28 +95,34 @@ <% end %>
<% end %> - -
- Description: - - <%= if @running do %> + Description: + + <%= if @running do %>
-
-
+
+
+
+ <% else %> + <%= if @label do %> + <%= @label %> <% else %> - <%= if @label do %> - <%= @label %> - <% else %> - Waiting for image input. - <% end %> + Waiting for image input. <% end %> + <% end %>
-
+
+ <%= if length(@displayed_list)>0 do %> +
+ surf +
<%= inspect(elt.label) %>
+
+ <% end %> +
diff --git a/mix.exs b/mix.exs index a63a8c2..bc00e3f 100644 --- a/mix.exs +++ b/mix.exs @@ -52,17 +52,19 @@ defmodule App.MixProject do {:telemetry_poller, "~> 1.0"}, {:jason, "~> 1.4"}, {:plug_cowboy, "~> 2.6.1"}, + {:req, "0.4.5"}, # Bumblebee imports {:bumblebee, "~> 0.4.2"}, - {:exla, "~> 0.6.1"}, - {:nx, "~> 0.6.2"}, + {:exla, "~> 0.6.4"}, + {:nx, "~> 0.6.4 "}, # Image + {:stb_image, "0.6.4"}, {:vix, "~> 0.24.0"}, # Testing - {:excoveralls, "~> 0.15", only: [:test, :dev]}, + {:excoveralls, "~> 0.15", only: [:test, :dev]} ] end diff --git a/mix.lock b/mix.lock index 6d15070..d496b47 100644 --- a/mix.lock +++ b/mix.lock @@ -13,10 +13,15 @@ "excoveralls": {:hex, :excoveralls, "0.18.0", "b92497e69465dc51bc37a6422226ee690ab437e4c06877e836f1c18daeb35da9", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1109bb911f3cb583401760be49c02cbbd16aed66ea9509fc5479335d284da60b"}, "exla": {:hex, :exla, "0.6.4", "24a46884696c4904d7c8f87a41461a7460f5f118ca171062044d187b32fae279", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nx, "~> 0.6.4", [hex: :nx, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:xla, "~> 0.5.0", [hex: :xla, repo: "hexpm", optional: false]}], "hexpm", "09b3608b55941736f222388da7611f33fe4b0bb308119cdf2f32f50b924d0ad6"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, + "finch": {:hex, :finch, "0.16.0", "40733f02c89f94a112518071c0a91fe86069560f5dbdb39f9150042f44dcfb1a", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f660174c4d519e5fec629016054d60edd822cdfe2b7270836739ac2f97735ec5"}, "floki": {:hex, :floki, "0.35.2", "87f8c75ed8654b9635b311774308b2760b47e9a579dabf2e4d5f1e1d42c39e0b", [:mix], [], "hexpm", "6b05289a8e9eac475f644f09c2e4ba7e19201fd002b89c28c1293e7bd16773d9"}, "heroicons": {:hex, :heroicons, "0.5.3", "ee8ae8335303df3b18f2cc07f46e1cb6e761ba4cf2c901623fbe9a28c0bc51dd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:phoenix_live_view, ">= 0.18.2", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "a210037e8a09ac17e2a0a0779d729e89c821c944434c3baa7edfc1f5b32f3502"}, + "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, + "mint": {:hex, :mint, "1.5.1", "8db5239e56738552d85af398798c80648db0e90f343c8469f6c6d8898944fb6f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4a63e1e76a7c3956abd2c72f370a0d0aecddc3976dea5c27eccbecfa5e7d5b1e"}, + "nimble_options": {:hex, :nimble_options, "1.0.2", "92098a74df0072ff37d0c12ace58574d26880e522c22801437151a159392270e", [:mix], [], "hexpm", "fd12a8db2021036ce12a309f26f564ec367373265b53e25403f0ee697380f1b8"}, + "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"}, "nx": {:hex, :nx, "0.6.4", "948d9f42f81e63fc901d243ac0a985c8bb87358be62e27826cfd67f58bc640af", [:mix], [{:complex, "~> 0.5", [hex: :complex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bb9c2e2e3545b5eb4739d69046a988daaa212d127dba7d97801c291616aff6d6"}, "nx_image": {:hex, :nx_image, "0.1.1", "69cf0d2fd873d12b028583aa49b5e0a25f6aca307afc337a5d871851a20fba1d", [:mix], [{:nx, "~> 0.4", [hex: :nx, repo: "hexpm", optional: false]}], "hexpm", "55c8206a822237f6027168f11214e3887263c5b8a1f8e0634eea82c96e5093e3"}, "nx_signal": {:hex, :nx_signal, "0.2.0", "e1ca0318877b17c81ce8906329f5125f1e2361e4c4235a5baac8a95ee88ea98e", [:mix], [{:nx, "~> 0.6", [hex: :nx, repo: "hexpm", optional: false]}], "hexpm", "7247e5e18a177a59c4cb5355952900c62fdeadeb2bad02a9a34237b68744e2bb"}, @@ -26,14 +31,16 @@ "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.1", "92a37acf07afca67ac98bd326532ba8f44ad7d4bdf3e4361b03f7f02594e5ae9", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "be494fd1215052729298b0e97d5c2ce8e719c00854b82cd8cf15c1cd7fcf6294"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, "phoenix_template": {:hex, :phoenix_template, "1.0.3", "32de561eefcefa951aead30a1f94f1b5f0379bc9e340bb5c667f65f1edfa4326", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "16f4b6588a4152f3cc057b9d0c0ba7e82ee23afa65543da535313ad8d25d8e2c"}, - "plug": {:hex, :plug, "1.15.1", "b7efd81c1a1286f13efb3f769de343236bd8b7d23b4a9f40d3002fc39ad8f74c", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "459497bd94d041d98d948054ec6c0b76feacd28eec38b219ca04c0de13c79d30"}, + "plug": {:hex, :plug, "1.15.2", "94cf1fa375526f30ff8770837cb804798e0045fd97185f0bb9e5fcd858c792a3", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02731fa0c2dcb03d8d21a1d941bdbbe99c2946c0db098eee31008e04c6283615"}, "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"}, "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, "polaris": {:hex, :polaris, "0.1.0", "dca61b18e3e801ecdae6ac9f0eca5f19792b44a5cb4b8d63db50fc40fc038d22", [:mix], [{:nx, "~> 0.5", [hex: :nx, repo: "hexpm", optional: false]}], "hexpm", "13ef2b166650e533cb24b10e2f3b8ab4f2f449ba4d63156e8c569527f206e2c2"}, "progress_bar": {:hex, :progress_bar, "3.0.0", "f54ff038c2ac540cfbb4c2bfe97c75e7116ead044f3c2b10c9f212452194b5cd", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "6981c2b25ab24aecc91a2dc46623658e1399c21a2ae24db986b90d678530f2b7"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "req": {:hex, :req, "0.4.5", "2071bbedd280f107b9e33e1ddff2beb3991ec1ae06caa2cca2ab756393d8aca5", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "dd23e9c7303ddeb2dee09ff11ad8102cca019e38394456f265fb7b9655c64dd8"}, "rustler_precompiled": {:hex, :rustler_precompiled, "0.7.0", "5d0834fc06dbc76dd1034482f17b1797df0dba9b491cef8bb045fcaca94bcade", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "fdf43a6835f4e4de5bfbc4c019bfb8c46d124bd4635fefa3e20d9a2bbbec1512"}, "safetensors": {:hex, :safetensors, "0.1.2", "849434fea20b2ed14b92e74205a925d86039c4ef53efe861e5c7b574c3ba8fa6", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nx, "~> 0.5", [hex: :nx, repo: "hexpm", optional: false]}], "hexpm", "298a5c82e34fc3b955464b89c080aa9a2625a47d69148d51113771e19166d4e0"}, + "stb_image": {:hex, :stb_image, "0.6.4", "d7cf19791e80d2d18ef1a5f3f6a8a828e76871f6bb4c20d860a5fa58779c70aa", [:make, :mix], [{:cc_precompiler, "~> 0.1.0", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7.0", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}, {:nx, "~> 0.4", [hex: :nx, repo: "hexpm", optional: true]}], "hexpm", "2719309d9e59271c0f92cfae5bd569690bbbad48bcb9b38b2b3d9d8856fa2d47"}, "tailwind": {:hex, :tailwind, "0.2.2", "9e27288b568ede1d88517e8c61259bc214a12d7eed271e102db4c93fcca9b2cd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "ccfb5025179ea307f7f899d1bb3905cd0ac9f687ed77feebc8f67bdca78565c4"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, @@ -41,7 +48,7 @@ "tokenizers": {:hex, :tokenizers, "0.4.0", "140283ca74a971391ddbd83cd8cbdb9bd03736f37a1b6989b82d245a95e1eb97", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, ">= 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.6", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "ef1a9824f5a893cd3b831c0e5b3d72caa250d2ec462035cc6afef6933b13a82e"}, "unpickler": {:hex, :unpickler, "0.1.0", "c2262c0819e6985b761e7107546cef96a485f401816be5304a65fdd200d5bd6a", [:mix], [], "hexpm", "e2b3f61e62406187ac52afead8a63bfb4e49394028993f3c4c42712743cab79e"}, "unzip": {:hex, :unzip, "0.8.0", "ee21d87c21b01567317387dab4228ac570ca15b41cfc221a067354cbf8e68c4d", [:mix], [], "hexpm", "ffa67a483efcedcb5876971a50947222e104d5f8fea2c4a0441e6f7967854827"}, - "vix": {:hex, :vix, "0.24.0", "f684377433772fb989bb65f3897d1833fd22437b33bd3704a2f066f4aeb1e396", [:make, :mix], [{:castore, "~> 1.0 or ~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:cc_precompiler, "~> 0.2 or ~> 0.1.4", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.8 or ~> 0.7.3", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}], "hexpm", "20f09be95f04ee96bf6af497bc11f0d29e71edd7ec615421485d99936cbac4ea"}, + "vix": {:hex, :vix, "0.24.0", "f684377433772fb989bb65f3897d1833fd22437b33bd3704a2f066f4aeb1e396", [:make, :mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:cc_precompiler, "~> 0.1.4 or ~> 0.2", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7.3 or ~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}], "hexpm", "20f09be95f04ee96bf6af497bc11f0d29e71edd7ec615421485d99936cbac4ea"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, "websock_adapter": {:hex, :websock_adapter, "0.5.5", "9dfeee8269b27e958a65b3e235b7e447769f66b5b5925385f5a569269164a210", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b977ba4a01918acbf77045ff88de7f6972c2a009213c515a445c48f224ffce9"}, "xla": {:hex, :xla, "0.5.1", "8ba4c2c51c1a708ff54e9d4f88158c1a75b7f2cb3e5db02bf222b5b3852afffd", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "82a2490f6e9a76c8a29d1aedb47f07c59e3d5081095eac5a74db34d46c8212bc"}, From 5fbcb002af689086f3e289850f7626927c53d4fe Mon Sep 17 00:00:00 2001 From: Neven DREAN Date: Wed, 15 Nov 2023 13:58:40 +0100 Subject: [PATCH 2/3] example --- lib/app_web/live/page_live.html.heex | 178 ++++++++++++++------------- mix.exs | 1 - 2 files changed, 91 insertions(+), 88 deletions(-) diff --git a/lib/app_web/live/page_live.html.heex b/lib/app_web/live/page_live.html.heex index dd5f9c2..6bec352 100644 --- a/lib/app_web/live/page_live.html.heex +++ b/lib/app_web/live/page_live.html.heex @@ -18,111 +18,115 @@ >Bumblebee.

-
-
-
-
- - <%= if @image_preview_base64 do %> -
- -
- <% else %> +
+
+
+ + <%= if @image_preview_base64 do %> +
+ +
+ <% else %> + +
+ +

or drag and drop

+
+

PNG, JPG, GIF up to 5MB

+ <% end %> +
+
+
+
+ + <%= for entry <- @uploads.image_list.entries do %> +
+ <%= for err <- upload_errors(@uploads.image_list, entry) do %> +
+
+
-
- -

or drag and drop

-
-

PNG, JPG, GIF up to 5MB

- <% end %> +
+
+

+ <%= error_to_string(err) %> +

+
-
+ <% end %>
- - <%= for entry <- @uploads.image_list.entries do %> -
- <%= for err <- upload_errors(@uploads.image_list, entry) do %> -
-
-
- -
-
-

- <%= error_to_string(err) %> -

-
-
-
- <% end %> -
- <% end %> - -
- Description: - - <%= if @running do %> -
-
-
-
+ <% end %> + +
+ Description: + + <%= if @running do %> +
+
+
+
+ <% else %> + <%= if @label do %> + <%= @label %> <% else %> - <%= if @label do %> - <%= @label %> - <% else %> - Waiting for image input. - <% end %> + Waiting for image input. <% end %> -
+ <% end %>
-
- <%= if length(@displayed_list)>0 do %> -
- surf -
<%= inspect(elt.label) %>
-
+
+<%= if length(@displayed_list)>0 do %> +
+ <%= for elt <- @displayed_list do %> +
+ Image +
+
<%= inspect(elt.label) %>
+
+
<% end %>
-
+<% end %> + +
diff --git a/mix.exs b/mix.exs index bc00e3f..69ad386 100644 --- a/mix.exs +++ b/mix.exs @@ -60,7 +60,6 @@ defmodule App.MixProject do {:nx, "~> 0.6.4 "}, # Image - {:stb_image, "0.6.4"}, {:vix, "~> 0.24.0"}, # Testing From 369061dd8d1682b928191104d9a85234a0e31a7b Mon Sep 17 00:00:00 2001 From: Neven DREAN Date: Wed, 15 Nov 2023 14:42:08 +0100 Subject: [PATCH 3/3] example --- lib/app_web/live/page_live.ex | 9 ++++----- lib/app_web/live/page_live.html.heex | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/app_web/live/page_live.ex b/lib/app_web/live/page_live.ex index dc6a1bf..dfd84ba 100644 --- a/lib/app_web/live/page_live.ex +++ b/lib/app_web/live/page_live.ex @@ -9,7 +9,7 @@ defmodule AppWeb.PageLive do @impl true def mount(_params, _session, socket) do - Process.send_after(self(), :populate_list, 3_000) + Process.send_after(self(), :example_list, 3_000) {:ok, socket @@ -89,7 +89,7 @@ defmodule AppWeb.PageLive do Map.get(assigns, :task_ref) == ref -> {:noreply, assign(socket, label: label, running: false)} - img = Map.get(assigns, :pre_list_tasks) |> Enum.find(&(&1.ref == ref)) -> + img = Map.get(assigns, :example_list_tasks) |> Enum.find(&(&1.ref == ref)) -> {:noreply, assign(socket, displayed_list: [%{url: img.url, label: label} | assigns.displayed_list], @@ -98,15 +98,14 @@ defmodule AppWeb.PageLive do )} true -> - nil {:noreply, socket} end end - def handle_info(:populate_list, socket) do + def handle_info(:example_list, socket) do tasks = @unsplashes |> Enum.map(&handle_image/1) - {:noreply, assign(socket, pre_list_tasks: tasks)} + {:noreply, assign(socket, example_list_tasks: tasks)} end def handle_image(url) do diff --git a/lib/app_web/live/page_live.html.heex b/lib/app_web/live/page_live.html.heex index 6bec352..3ae7383 100644 --- a/lib/app_web/live/page_live.html.heex +++ b/lib/app_web/live/page_live.html.heex @@ -1,4 +1,4 @@ -<.flash_group flash={@flash} /> +<%!-- <.flash_group flash={@flash} /> --%>
@@ -120,7 +120,7 @@
<%= for elt <- @displayed_list do %>
- Image + Image
<%= inspect(elt.label) %>