-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Adding rest of initial setup and README. #1
- Loading branch information
1 parent
105b434
commit c8acd88
Showing
23 changed files
with
1,623 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[ | ||
import_deps: [:phoenix], | ||
plugins: [Phoenix.LiveView.HTMLFormatter], | ||
inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}"] | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,37 @@ | ||
/_build | ||
/cover | ||
/deps | ||
/doc | ||
# The directory Mix will write compiled artifacts to. | ||
/_build/ | ||
|
||
# If you run "mix test --cover", coverage assets end up here. | ||
/cover/ | ||
|
||
# The directory Mix downloads your dependencies sources to. | ||
/deps/ | ||
|
||
# Where 3rd-party dependencies like ExDoc output generated docs. | ||
/doc/ | ||
|
||
# Ignore .fetch files in case you like to edit your project deps locally. | ||
/.fetch | ||
|
||
# If the VM crashes, it generates a dump, let's ignore it too. | ||
erl_crash.dump | ||
|
||
# Also ignore archive artifacts (built via "mix archive.build"). | ||
*.ez | ||
*.beam | ||
/config/*.secret.exs | ||
.elixir_ls/ | ||
|
||
# Temporary files, for example, from tests. | ||
/tmp/ | ||
|
||
# Ignore package tarball (built via "mix hex.build"). | ||
app-*.tar | ||
|
||
# Ignore assets that are produced by build tools. | ||
/priv/static/assets/ | ||
|
||
# Ignore digested assets cache. | ||
/priv/static/cache_manifest.json | ||
|
||
# In case you use Node.js/npm, you want to ignore these. | ||
npm-debug.log | ||
/assets/node_modules/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,257 @@ | ||
# image-classifier | ||
Classify images and attempt to extract data from or describe their contents | ||
<div align="center"> | ||
|
||
# Image classifier in `Elixir` | ||
|
||
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/dwyl/image-classifier/ci.yml?label=build&style=flat-square&branch=main) | ||
[![codecov.io](https://img.shields.io/codecov/c/github/dwyl/image-classifier/main.svg?style=flat-square)](https://codecov.io/github/dwyl/image-classifier?branch=main) | ||
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat-square)](https://github.com/dwyl/image-classifier/issues) | ||
[![HitCount](https://hits.dwyl.com/dwyl/image-classifier.svg?style=flat-square&show=unique)](https://hits.dwyl.com/dwyl/image-classifier) | ||
|
||
Classify your images using | ||
machine learning models | ||
within `Phoenix + Liveview`! | ||
|
||
</div> | ||
|
||
<br /> | ||
|
||
- [Image classifier in `Elixir`](#image-classifier-in-elixir) | ||
- [Why? 🤷](#why-) | ||
- [What? 💭](#what-) | ||
- [Who? 👤](#who-) | ||
- [How? 💻](#how-) | ||
- [Prerequisites](#prerequisites) | ||
- [0. Creating a fresh `Phoenix` project](#0-creating-a-fresh-phoenix-project) | ||
- [1. Adding `LiveView` capabilities to our project](#1-adding-liveview-capabilities-to-our-project) | ||
- [_Please_ Star the repo! ⭐️](#please-star-the-repo-️) | ||
|
||
|
||
<br /> | ||
|
||
# Why? 🤷 | ||
|
||
Building our | ||
[app](https://github.com/dwyl/app), | ||
we consider `images` an _essential_ | ||
medium of communication. | ||
|
||
By adding a way of classifying images, | ||
we make it *easy* for people | ||
to suggest meta tags to describe images | ||
so they become **searchable**. | ||
|
||
|
||
# What? 💭 | ||
|
||
This run-through will create a simple | ||
`Phoenix LiveView` web application | ||
that will allow you to choose/drag an image | ||
and classify the image. | ||
|
||
|
||
# Who? 👤 | ||
|
||
This tutorial is aimed at `LiveView` beginners | ||
that want to grasp how to do image classifying | ||
within a `Phoenix` application. | ||
|
||
If you are completely new to `Phoenix` and `LiveView`, | ||
we recommend you follow the **`LiveView` _Counter_ Tutorial**: | ||
[dwyl/phoenix-liveview-counter-tutorial](https://github.com/dwyl/phoenix-liveview-counter-tutorial) | ||
|
||
|
||
# How? 💻 | ||
|
||
In this chapter, we'll go over the development process | ||
of this small application. | ||
You'll learn how to do this *yourself*, | ||
so grab some coffee and let's get cracking! | ||
|
||
|
||
## Prerequisites | ||
|
||
This tutorial requires you have `Elixir` and `Phoenix` installed. | ||
If you you don't, please see | ||
[how to install Elixir](https://github.com/dwyl/learn-elixir#installation) | ||
and | ||
[Phoenix](https://hexdocs.pm/phoenix/installation.html#phoenix). | ||
|
||
We assume you know the basics of `Phoenix` | ||
and have *some* knowledge of how it works. | ||
If you don't, | ||
we *highly suggest* you follow our other tutorials first. | ||
e.g: | ||
[github.com/dwyl/**phoenix-chat-example**](https://github.com/dwyl/phoenix-chat-example) | ||
|
||
In addition to this, | ||
**_some_ knowledge of `AWS`** - | ||
what it is, what an `S3` bucket is/does - | ||
**is assumed**. | ||
|
||
> **Note**: if you have questions or get stuck, | ||
> please open an issue! | ||
> [/dwyl/image-classifier/issues](https://github.com/dwyl/image-classifier/issues) | ||
|
||
## 0. Creating a fresh `Phoenix` project | ||
|
||
Let's create a fresh `Phoenix` project. | ||
Run the following command in a given folder: | ||
|
||
```sh | ||
mix phx.new . --app app --no-dashboard --no-ecto --no-gettext --no-mailer | ||
``` | ||
|
||
We're running [`mix phx.new`](https://hexdocs.pm/phoenix/Mix.Tasks.Phx.New.html) | ||
to generate a new project without a dashboard | ||
and mailer (email) service, | ||
since we don't need those in our project. | ||
|
||
After this, | ||
if you run `mix phx.server` to run your server, | ||
you should be able to see the following page. | ||
|
||
<p align="center"> | ||
<img src="https://github.com/dwyl/imgup/assets/17494745/b40f4e79-e225-4226-8112-c490b5b4bf46"> | ||
</p> | ||
|
||
We're ready to start implementing! | ||
|
||
|
||
## 1. Adding `LiveView` capabilities to our project | ||
|
||
As it stands, | ||
our project is not using `LiveView`. | ||
Let's fix this. | ||
|
||
In `lib/app_web/router.ex`, | ||
change the `scope "/"` to the following. | ||
|
||
```elixir | ||
scope "/", AppWeb do | ||
pipe_through :browser | ||
|
||
live "/", ImgupLive | ||
end | ||
``` | ||
|
||
Instead of using the `PageController`, | ||
we are going to be creating `ImgupLive`, | ||
a `LiveView` file. | ||
|
||
Let's create our `LiveView` files. | ||
Inside `lib/app_web`, | ||
create a folder called `live` | ||
and create the following file | ||
`imgup_live.ex`. | ||
|
||
```elixir | ||
defmodule AppWeb.ImgupLive do | ||
use AppWeb, :live_view | ||
|
||
@impl true | ||
def mount(_params, _session, socket) do | ||
{:ok, | ||
socket | ||
|> assign(:uploaded_files, []) | ||
|> allow_upload(:image_list, accept: ~w(image/*), max_entries: 6, chunk_size: 64_000)} | ||
end | ||
end | ||
``` | ||
|
||
This is a simple `LiveView` controller | ||
with the `mount/3` function | ||
where we use the | ||
[`allow_upload/3`](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#allow_upload/3) | ||
function, | ||
which is needed to allow file uploads in `LiveView`. | ||
|
||
In the same `live` folder, | ||
create a file called `imgup_live.html.heex` | ||
and use the following code. | ||
|
||
```html | ||
<.flash_group flash={@flash} /> | ||
<div class="px-4 py-10 flex justify-center sm:px-6 sm:py-28 lg:px-8 xl:px-28 xl:py-32"> | ||
<div class="mx-auto max-w-xl w-[50vw] lg:mx-0"> | ||
<form> | ||
<div class="space-y-12"> | ||
<div class="border-b border-gray-900/10 pb-12"> | ||
<h2 class="text-base font-semibold leading-7 text-gray-900">Image Upload</h2> | ||
<p class="mt-1 text-sm leading-6 text-gray-600">Drag your images and they'll be uploaded to the cloud! ☁️</p> | ||
|
||
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6"> | ||
|
||
<div class="col-span-full"> | ||
<div class="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 px-6 py-10"> | ||
<div class="text-center"> | ||
<svg class="mx-auto h-12 w-12 text-gray-300" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"> | ||
<path fill-rule="evenodd" d="M1.5 6a2.25 2.25 0 012.25-2.25h16.5A2.25 2.25 0 0122.5 6v12a2.25 2.25 0 01-2.25 2.25H3.75A2.25 2.25 0 011.5 18V6zM3 16.06V18c0 .414.336.75.75.75h16.5A.75.75 0 0021 18v-1.94l-2.69-2.689a1.5 1.5 0 00-2.12 0l-.88.879.97.97a.75.75 0 11-1.06 1.06l-5.16-5.159a1.5 1.5 0 00-2.12 0L3 16.061zm10.125-7.81a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0z" clip-rule="evenodd" /> | ||
</svg> | ||
<div class="mt-4 flex text-sm leading-6 text-gray-600"> | ||
<label for="file-upload" class="relative cursor-pointer rounded-md bg-white font-semibold text-indigo-600 focus-within:outline-none focus-within:ring-2 focus-within:ring-indigo-600 focus-within:ring-offset-2 hover:text-indigo-500"> | ||
<span>Upload a file</span> | ||
<input id="file-upload" name="file-upload" type="file" class="sr-only"> | ||
</label> | ||
<p class="pl-1">or drag and drop</p> | ||
</div> | ||
<p class="text-xs leading-5 text-gray-600">PNG, JPG, GIF up to 10MB</p> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<div class="mt-6 flex items-center justify-end gap-x-6"> | ||
<button type="button" class="text-sm font-semibold leading-6 text-gray-900">Cancel</button> | ||
<button type="submit" class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Save</button> | ||
</div> | ||
</form> | ||
</div> | ||
</div> | ||
``` | ||
|
||
This is a simple HTML form that uses | ||
[`Tailwind CSS`](https://github.com/dwyl/learn-tailwind) | ||
to enhance the presentation of the upload form. | ||
We'll also remove the unused header of the page layout, | ||
while we're at it. | ||
|
||
Locate the file `lib/app_web/components/layouts/app.html.heex` | ||
and remove the `<header>` class. | ||
The file should only have the following code: | ||
|
||
```html | ||
<main class="px-4 py-20 sm:px-6 lg:px-8"> | ||
<div class="mx-auto max-w-2xl"> | ||
<.flash_group flash={@flash} /> | ||
<%= @inner_content %> | ||
</div> | ||
</main> | ||
``` | ||
|
||
Now you can safely delete the `lib/app_web/controllers` folder, | ||
which is no longer used. | ||
|
||
If you run `mix phx.server`, | ||
you should see the following screen: | ||
|
||
<p align="center"> | ||
<img src="https://github.com/dwyl/imgup/assets/17494745/5a3438fe-fa45-47f9-8cb2-9d6d405f55a0"> | ||
</p> | ||
|
||
This means we've successfully added `LiveView` | ||
and changed our view! | ||
We can now start implementing file uploads! 🗳️ | ||
|
||
> If you want to see the changes made to the project, | ||
> check [b414b11](https://github.com/dwyl/imgup/pull/55/commits). | ||
|
||
# _Please_ Star the repo! ⭐️ | ||
|
||
If you find this package/repo useful, | ||
please star on GitHub, so that we know! ⭐ | ||
|
||
Thank you! 🙏 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
@import "tailwindcss/base"; | ||
@import "tailwindcss/components"; | ||
@import "tailwindcss/utilities"; | ||
|
||
/* This file is for your main application CSS */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// If you want to use Phoenix channels, run `mix help phx.gen.channel` | ||
// to get started and then uncomment the line below. | ||
// import "./user_socket.js" | ||
|
||
// You can include dependencies in two ways. | ||
// | ||
// The simplest option is to put them in assets/vendor and | ||
// import them using relative paths: | ||
// | ||
// import "../vendor/some-package.js" | ||
// | ||
// Alternatively, you can `npm install some-package --prefix assets` and import | ||
// them using a path starting with the package name: | ||
// | ||
// import "some-package" | ||
// | ||
|
||
// Include phoenix_html to handle method=PUT/DELETE in forms and buttons. | ||
import "phoenix_html" | ||
// Establish Phoenix Socket and LiveView configuration. | ||
import {Socket} from "phoenix" | ||
import {LiveSocket} from "phoenix_live_view" | ||
import topbar from "../vendor/topbar" | ||
|
||
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") | ||
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}}) | ||
|
||
// Show progress bar on live navigation and form submits | ||
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) | ||
window.addEventListener("phx:page-loading-start", _info => topbar.show(300)) | ||
window.addEventListener("phx:page-loading-stop", _info => topbar.hide()) | ||
|
||
// connect if there are any LiveViews on the page | ||
liveSocket.connect() | ||
|
||
// expose liveSocket on window for web console debug logs and latency simulation: | ||
// >> liveSocket.enableDebug() | ||
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session | ||
// >> liveSocket.disableLatencySim() | ||
window.liveSocket = liveSocket | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// See the Tailwind configuration guide for advanced usage | ||
// https://tailwindcss.com/docs/configuration | ||
|
||
const plugin = require("tailwindcss/plugin") | ||
|
||
module.exports = { | ||
content: [ | ||
"./js/**/*.js", | ||
"../lib/*_web.ex", | ||
"../lib/*_web/**/*.*ex" | ||
], | ||
theme: { | ||
extend: { | ||
colors: { | ||
brand: "#FD4F00", | ||
} | ||
}, | ||
}, | ||
plugins: [ | ||
require("@tailwindcss/forms"), | ||
plugin(({addVariant}) => addVariant("phx-no-feedback", [".phx-no-feedback&", ".phx-no-feedback &"])), | ||
plugin(({addVariant}) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])), | ||
plugin(({addVariant}) => addVariant("phx-submit-loading", [".phx-submit-loading&", ".phx-submit-loading &"])), | ||
plugin(({addVariant}) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"])) | ||
] | ||
} |
Oops, something went wrong.