Permalink
Browse files

Merge pull request #1 from nerves-build/analyzer-wip

incorporate ocv_photo_analyzer into Flow
  • Loading branch information...
stwf committed Apr 5, 2018
2 parents 435bb98 + 557d284 commit 03d632e3a007c45554ea7701c14a3abdced800d9
@@ -73,7 +73,7 @@ function react_to_payload(pyld) {
json: pyld.history,
keys: {
x: "time",
value: ["ingested", "hash", "persist", "finfo", "exif", "geolocate", "geopersist", "completed"],
value: ["ingested", "hash", "persist", "finfo", "exif", "analyze", "geolocate", "geopersist", "completed"],
},
order: 'desc',
});
@@ -111,7 +111,7 @@ var lineChart = c3.generate({
json: [],
keys: {
x: "time",
value: ["ingested", "hash", "persist", "finfo", "exif", "geolocate", "geopersist", "completed"],
value: ["ingested", "hash", "persist", "finfo", "exif", "analyze", "geolocate", "geopersist", "completed"],
},
order: 'desc'
},
@@ -0,0 +1,17 @@
defmodule PhotoFlowExample.Flows.Analyzer do

alias PhotoFlowExample.Flows.FlowPhoto
alias PhotoFlowExample.Photos

def execute(%FlowPhoto{original_path: path, photo: photo} = item) do
an_data = OcvPhotoAnalyzer.analyze(path)
{:ok, anal} = Photos.create_analysis(%{
photo_id: photo.id,
histogram: an_data.histogram,
color_one: Enum.at(an_data.dominant, 0),
color_two: Enum.at(an_data.dominant, 1),
color_three: Enum.at(an_data.dominant, 2)
})
FlowPhoto.add_analysis(item, anal)
end
end
@@ -1,5 +1,5 @@
defmodule PhotoFlowExample.Flows.Flow do
alias PhotoFlowExample.Flows.{ExifInfo, FileInfo, Hasher, Geonames, FlowPhoto, Persister}
alias PhotoFlowExample.Flows.{ExifInfo, FileInfo, Hasher, Geonames, FlowPhoto, Persister, Analyzer}
alias PhotoFlowExample.FolderScan

def start_flow do
@@ -12,6 +12,7 @@ defmodule PhotoFlowExample.Flows.Flow do
|> Flow.reject(&Persister.not_persisted(&1))
|> Flow.map(&FileInfo.execute(&1))
|> Flow.map(&ExifInfo.execute(&1))
|> Flow.map(&Analyzer.execute(&1))
|> Flow.map(&Geonames.fetch(&1))
|> Flow.partition(key: fn p -> Geonames.place_key(p) end, stages: 6)
|> Flow.map(&Geonames.get_or_create_place(&1))
@@ -5,11 +5,12 @@ defmodule PhotoFlowExample.Flows.FlowPhoto do
place: nil,
geodata: nil,
exif_info: nil,
file_info: nil
file_info: nil,
analysis: nil

alias PhotoFlowExample.Flows.{FlowPhoto, FileInfo, ExifInfo}
alias PhotoFlowExample.LoudCounter
alias PhotoFlowExample.Photos.Photo
alias PhotoFlowExample.Photos.{Photo, Analysis}
alias PhotoFlowExample.Locations.Place

@doc false
@@ -31,6 +32,11 @@ defmodule PhotoFlowExample.Flows.FlowPhoto do
%{fp | file_info: info}
end

def add_analysis(%FlowPhoto{} = fp, %Analysis{} = data) do
LoudCounter.increment_tag(:analyze, 1)
%{fp | analysis: data}
end

def add_exif_info(%FlowPhoto{} = fp, %ExifInfo{} = info) do
LoudCounter.increment_tag(:exif, 1)
%{fp | exif_info: info}
@@ -33,7 +33,10 @@ defmodule PhotoFlowExample.Flows.Persister do
end

def update_photo(%FlowPhoto{photo: photo} = item) do
Photos.update_photo(photo, photo_attributes(item))
attr = photo_attributes(item)
|> place_attributes(item)

Photos.update_photo(photo, attr)
item
end

@@ -57,7 +60,7 @@ defmodule PhotoFlowExample.Flows.Persister do
original_path: path,
file_info: finfo,
hash: hash,
exif_info: exifs
exif_info: exifs,
}) do
%{
name: Path.basename(path),
@@ -74,4 +77,10 @@ defmodule PhotoFlowExample.Flows.Persister do
exif_data: exifs.exif_data
}
end

defp place_attributes(attr, %FlowPhoto{place: nil}), do: attr

defp place_attributes(attr, %FlowPhoto{place: place}) do
Map.merge(attr, %{place_id: place.id})
end
end
@@ -0,0 +1,25 @@
defmodule PhotoFlowExample.Photos.Analysis do
use Ecto.Schema
import Ecto.Changeset
alias PhotoFlowExample.Photos.Photo
alias PhotoFlowExample.Photos.Analysis


schema "analyses" do
field :color_one, :map
field :color_two, :map
field :color_three, :map
field :histogram, :map

belongs_to(:photo, Photo)

timestamps()
end


@doc false
def changeset(%Analysis{} = analysis, attrs) do
analysis
|> cast(attrs, [:histogram, :color_one, :color_two, :color_three])
end
end
@@ -3,6 +3,7 @@ defmodule PhotoFlowExample.Photos.Photo do
import Ecto.Changeset
use Arc.Ecto.Schema
alias PhotoFlowExample.Photos.Photo
alias PhotoFlowExample.Photos.Analysis
alias PhotoFlowExample.Locations.Place

schema "photos" do
@@ -22,7 +23,7 @@ defmodule PhotoFlowExample.Photos.Photo do
field(:content, PhotoFlowExample.Photos.Content.Type)

belongs_to(:place, Place)

has_one(:analysis, Analysis)
timestamps()
end

@@ -54,4 +54,100 @@ defmodule PhotoFlowExample.Photos do
def change_photo(%Photo{} = photo) do
Photo.changeset(photo, %{})
end

alias PhotoFlowExample.Photos.Analysis

@doc """
Returns the list of analyses.
## Examples
iex> list_analyses()
[%Analysis{}, ...]
"""
def list_analyses do
Repo.all(Analysis)
end

@doc """
Gets a single analysis.
Raises `Ecto.NoResultsError` if the Analysis does not exist.
## Examples
iex> get_analysis!(123)
%Analysis{}
iex> get_analysis!(456)
** (Ecto.NoResultsError)
"""
def get_analysis!(id), do: Repo.get!(Analysis, id)

@doc """
Creates a analysis.
## Examples
iex> create_analysis(%{field: value})
{:ok, %Analysis{}}
iex> create_analysis(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_analysis(attrs \\ %{}) do
%Analysis{}
|> Analysis.changeset(attrs)
|> Repo.insert()
end

@doc """
Updates a analysis.
## Examples
iex> update_analysis(analysis, %{field: new_value})
{:ok, %Analysis{}}
iex> update_analysis(analysis, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_analysis(%Analysis{} = analysis, attrs) do
analysis
|> Analysis.changeset(attrs)
|> Repo.update()
end

@doc """
Deletes a Analysis.
## Examples
iex> delete_analysis(analysis)
{:ok, %Analysis{}}
iex> delete_analysis(analysis)
{:error, %Ecto.Changeset{}}
"""
def delete_analysis(%Analysis{} = analysis) do
Repo.delete(analysis)
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking analysis changes.
## Examples
iex> change_analysis(analysis)
%Ecto.Changeset{source: %Analysis{}}
"""
def change_analysis(%Analysis{} = analysis) do
Analysis.changeset(analysis, %{})
end
end
@@ -43,6 +43,7 @@ defmodule PhotoFlowExample.Mixfile do
{:mariaex, "~> 0.1"},
{:gettext, "~> 0.11"},
{:cowboy, "~> 1.0"},
{:ocv_photo_analyzer, "~> 1.0"},
{:flow, "~> 0.11"},
{:timex, "~> 3.1"},
{:arc, "~> 0.8.0"},
@@ -1,5 +1,4 @@
%{
"arc": {:hex, :arc, "0.8.0", "bb7cf8ea50f30f9c2bb357270c074def42a7ec6a3b4605be731cc5faf8fde6fd", [:mix], [{:ex_aws, "~> 1.1", [hex: :ex_aws, optional: true]}, {:httpoison, "~> 0.11", [hex: :httpoison, optional: false]}, {:poison, "~> 2.2 or ~> 3.1", [hex: :poison, optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, optional: true]}]},
%{"arc": {:hex, :arc, "0.8.0", "bb7cf8ea50f30f9c2bb357270c074def42a7ec6a3b4605be731cc5faf8fde6fd", [:mix], [{:ex_aws, "~> 1.1", [hex: :ex_aws, optional: true]}, {:httpoison, "~> 0.11", [hex: :httpoison, optional: false]}, {:poison, "~> 2.2 or ~> 3.1", [hex: :poison, optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, optional: true]}]},
"arc_ecto": {:hex, :arc_ecto, "0.7.0", "428ed7ea4ed0be8996d8fc6e9f651d3e26fe9c9063f26cbf6731c865369845d3", [:mix], [{:arc, "~> 0.8.0", [hex: :arc, optional: false]}, {:ecto, "~> 2.0", [hex: :ecto, optional: false]}]},
"calliope": {:hex, :calliope, "0.4.2", "29d8585331f3c04f95d6e2f7c8367d660cfb6c2dc031bd3d22afb7e7201eb5c6", [:mix], []},
"certifi": {:hex, :certifi, "1.2.1", "c3904f192bd5284e5b13f20db3ceac9626e14eeacfbb492e19583cf0e37b22be", [:rebar3], []},
@@ -10,22 +9,24 @@
"db_connection": {:hex, :db_connection, "1.1.2", "2865c2a4bae0714e2213a0ce60a1b12d76a6efba0c51fbda59c9ab8d1accc7a8", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, optional: true]}]},
"decimal": {:hex, :decimal, "1.4.1", "ad9e501edf7322f122f7fc151cce7c2a0c9ada96f2b0155b8a09a795c2029770", [:mix], []},
"ecto": {:hex, :ecto, "2.2.7", "2074106ff4a5cd9cb2b54b12ca087c4b659ddb3f6b50be4562883c1d763fb031", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, optional: true]}]},
"elixir_make": {:hex, :elixir_make, "0.4.1", "6628b86053190a80b9072382bb9756a6c78624f208ec0ff22cb94c8977d80060", [:mix], []},
"ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], []},
"ex_rated": {:hex, :ex_rated, "1.3.1", "a835463a2a92e7b8eb40622f3041901fd813165dc0475f9176f79d80b9a6627c", [:mix], [{:ex2ms, "~> 1.5", [hex: :ex2ms, optional: false]}]},
"exexif": {:git, "https://github.com/TehSnappy/exexif.git", "4cb642b0dafc801a48bf027c7e44c66a0f0cd386", []},
"file_system": {:hex, :file_system, "0.2.2", "7f1e9de4746f4eb8a4ca8f2fbab582d84a4e40fa394cce7bfcb068b988625b06", [:mix], []},
"flow": {:hex, :flow, "0.12.0", "32c5a5f3ff6693e004b6c17a8c64dce2f8cdaf9564912d79427176013a586ab6", [:mix], [{:gen_stage, "~> 0.12.0", [hex: :gen_stage, optional: false]}]},
"gen_stage": {:hex, :gen_stage, "0.12.2", "e0e347cbb1ceb5f4e68a526aec4d64b54ad721f0a8b30aa9d28e0ad749419cbb", [:mix], []},
"geonames": {:git, "https://github.com/TehSnappy/geonames-elixir.git", "85241c9fd45946e239880484d2adebafc04e5023", []},
"geonames": {:git, "https://github.com/TehSnappy/geonames-elixir.git", "0b8011c08b9bbe34131dcbded10ebbc4d2b6a6dc", []},
"gettext": {:hex, :gettext, "0.14.0", "1a019a2e51d5ad3d126efe166dcdf6563768e5d06c32a99ad2281a1fa94b4c72", [:mix], []},
"hackney": {:hex, :hackney, "1.8.6", "21a725db3569b3fb11a6af17d5c5f654052ce9624219f1317e8639183de4a423", [:rebar3], [{:certifi, "1.2.1", [hex: :certifi, optional: false]}, {:idna, "5.0.2", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, optional: false]}]},
"hammer": {:hex, :hammer, "3.0.0", "c2bd92ccbbd0370d091a8337737aedd25e6715a7de759ba1ae6d1bad9fd76ca8", [:mix], [], "hexpm"},
"hammer": {:hex, :hammer, "3.0.0", "c2bd92ccbbd0370d091a8337737aedd25e6715a7de759ba1ae6d1bad9fd76ca8", [:mix], []},
"httpoison": {:hex, :httpoison, "0.11.2", "9e59f17a473ef6948f63c51db07320477bad8ba88cf1df60a3eee01150306665", [:mix], [{:hackney, "~> 1.8.0", [hex: :hackney, optional: false]}]},
"idna": {:hex, :idna, "5.0.2", "ac203208ada855d95dc591a764b6e87259cb0e2a364218f215ad662daa8cd6b4", [:rebar3], [{:unicode_util_compat, "0.2.0", [hex: :unicode_util_compat, optional: false]}]},
"mariaex": {:hex, :mariaex, "0.8.3", "bf51ff4d480f68400bad69d1ebe778b6edbcafa4dd0429826ae1dd89cb90c8ad", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, optional: false]}]},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []},
"mime": {:hex, :mime, "1.2.0", "78adaa84832b3680de06f88f0997e3ead3b451a440d183d688085be2d709b534", [:mix], []},
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], []},
"ocv_photo_analyzer": {:hex, :ocv_photo_analyzer, "1.0.1", "952b9bddfa5241595ea0ee944ef2fbd4977c6fd059724e1e758909e044f1476c", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, optional: false]}, {:porcelain, "~> 2.0", [hex: :porcelain, optional: false]}]},
"phoenix": {:hex, :phoenix, "1.3.0", "1c01124caa1b4a7af46f2050ff11b267baa3edb441b45dbf243e979cd4c5891b", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, optional: false]}]},
"phoenix_ecto": {:hex, :phoenix_ecto, "3.3.0", "702f6e164512853d29f9d20763493f2b3bcfcb44f118af2bc37bb95d0801b480", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, optional: true]}, {:plug, "~> 1.0", [hex: :plug, optional: false]}]},
"phoenix_haml": {:hex, :phoenix_haml, "0.2.3", "432b689ebb03dc821f00ae0ae5fb22e814aa8704e599763cbde538daf9f389f6", [:mix], [{:calliope, "~> 0.4.1", [hex: :calliope, optional: false]}, {:phoenix, "~> 1.1", [hex: :phoenix, optional: false]}, {:phoenix_html, "~> 2.3", [hex: :phoenix_html, optional: false]}]},
@@ -35,10 +36,10 @@
"plug": {:hex, :plug, "1.4.3", "236d77ce7bf3e3a2668dc0d32a9b6f1f9b1f05361019946aae49874904be4aed", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, optional: true]}, {:mime, "~> 1.0", [hex: :mime, optional: false]}]},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], []},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], []},
"porcelain": {:hex, :porcelain, "2.0.3", "2d77b17d1f21fed875b8c5ecba72a01533db2013bd2e5e62c6d286c029150fdc", [:mix], []},
"postgrex": {:hex, :postgrex, "0.13.3", "c277cfb2a9c5034d445a722494c13359e361d344ef6f25d604c2353185682bfc", [:mix], [{:connection, "~> 1.0", [hex: :connection, optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, optional: false]}]},
"ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], []},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []},
"timex": {:hex, :timex, "3.1.24", "d198ae9783ac807721cca0c5535384ebdf99da4976be8cefb9665a9262a1e9e3", [:mix], [{:combine, "~> 0.7", [hex: :combine, optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, optional: false]}]},
"tzdata": {:hex, :tzdata, "0.5.14", "56f05ea3dd87db946966ab3c7168c0b35025c7ee0e9b4fc130a04631f5611eb1", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, optional: false]}]},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.2.0", "dbbccf6781821b1c0701845eaf966c9b6d83d7c3bfc65ca2b78b88b8678bfa35", [:rebar3], []},
}
"unicode_util_compat": {:hex, :unicode_util_compat, "0.2.0", "dbbccf6781821b1c0701845eaf966c9b6d83d7c3bfc65ca2b78b88b8678bfa35", [:rebar3], []}}
@@ -0,0 +1,15 @@
defmodule PhotoFlowExample.Repo.Migrations.CreateAnalyses do
use Ecto.Migration

def change do
create table(:analyses) do
add :histogram, :string
add :color_one, :string
add :color_two, :string
add :color_three, :string
add :photo_id, :integer

timestamps()
end
end
end
@@ -0,0 +1,67 @@
defmodule PhotoFlowExample.PhotosTest do
use PhotoFlowExample.DataCase

alias PhotoFlowExample.Photos

describe "analyses" do
alias PhotoFlowExample.Photos.Analysis

@valid_attrs %{colors: [], histogram: %{}}
@update_attrs %{colors: [], histogram: %{}}
@invalid_attrs %{colors: nil, histogram: nil}

def analysis_fixture(attrs \\ %{}) do
{:ok, analysis} =
attrs
|> Enum.into(@valid_attrs)
|> Photos.create_analysis()

analysis
end

test "list_analyses/0 returns all analyses" do
analysis = analysis_fixture()
assert Photos.list_analyses() == [analysis]
end

test "get_analysis!/1 returns the analysis with given id" do
analysis = analysis_fixture()
assert Photos.get_analysis!(analysis.id) == analysis
end

test "create_analysis/1 with valid data creates a analysis" do
assert {:ok, %Analysis{} = analysis} = Photos.create_analysis(@valid_attrs)
assert analysis.colors == []
assert analysis.histogram == %{}
end

test "create_analysis/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Photos.create_analysis(@invalid_attrs)
end

test "update_analysis/2 with valid data updates the analysis" do
analysis = analysis_fixture()
assert {:ok, analysis} = Photos.update_analysis(analysis, @update_attrs)
assert %Analysis{} = analysis
assert analysis.colors == []
assert analysis.histogram == %{}
end

test "update_analysis/2 with invalid data returns error changeset" do
analysis = analysis_fixture()
assert {:error, %Ecto.Changeset{}} = Photos.update_analysis(analysis, @invalid_attrs)
assert analysis == Photos.get_analysis!(analysis.id)
end

test "delete_analysis/1 deletes the analysis" do
analysis = analysis_fixture()
assert {:ok, %Analysis{}} = Photos.delete_analysis(analysis)
assert_raise Ecto.NoResultsError, fn -> Photos.get_analysis!(analysis.id) end
end

test "change_analysis/1 returns a analysis changeset" do
analysis = analysis_fixture()
assert %Ecto.Changeset{} = Photos.change_analysis(analysis)
end
end
end
Oops, something went wrong.

0 comments on commit 03d632e

Please sign in to comment.