Current section
Files
Jump to
Current section
Files
lib/veritaserum.ex
defmodule Veritaserum do
@moduledoc """
Sentiment analisis based on AFINN-165, emojis and some enhancements.
Also supports:
- emojis (❤️, 😱...)
- boosters (*very*, *really*...)
- negators (*don't*, *not*...).
"""
alias Veritaserum.Evaluator
@spec analyze(List.t) :: Integer.t
def analyze(input) when is_list(input) do
input
|> Stream.map(&analyze/1)
|> Enum.to_list
end
@doc """
Returns a sentiment value for the given text
iex> Veritaserum.analyze(["I ❤️ Veritaserum", "Veritaserum is really awesome"])
[3, 5]
iex> Veritaserum.analyze("I love Veritaserum")
3
"""
@spec analyze(String.t) :: Integer.t
def analyze(input) do
input
|> clean
|> String.split
|> split_on_emoticons
|> Enum.map(&String.trim/1)
|> analyze_list()
|> Enum.reduce(0, &(&1 + &2))
end
defp analyze_list([head | tail]) do
analyze_list(tail, head, [analyze_word(head)])
end
defp analyze_list([head | tail], previous, result) do
analyze_list(tail, head, [analyze_word(head, previous) | result])
end
defp analyze_list([], _, result), do: result
defp analyze_word(word) do
with nil <- Evaluator.evaluate_emoticon(word),
nil <- Evaluator.evaluate_word(word),
do: 0
end
defp analyze_word(word, previous) do
case Evaluator.evaluate_negator(previous) do
1 -> - analyze_word(word)
nil -> analyze_word_for_boosters(word, previous)
end
end
defp analyze_word_for_boosters(word, previous) do
case Evaluator.evaluate_booster(previous) do
nil -> analyze_word(word)
val -> word |> analyze_word |> apply_booster(val)
end
end
defp apply_booster(word_value, booster) when word_value > 0, do: word_value + booster
defp apply_booster(word_value, booster) when word_value < 0, do: word_value - booster
defp apply_booster(word_value, _booster), do: word_value
defp clean(text) do
text
|> String.replace(~r/\n/, " ")
|> String.downcase
|> String.replace(~r/[.,\/#!$%\^&\*;:{}=_`\"~()]/, " ")
|> String.replace(~r/ {2,}/, " ")
end
defp split_on_emoticons(text_list) when is_list(text_list) do
split_on_emoticons(Evaluator.emoticon_list, text_list)
end
defp split_on_emoticons([head | tail], text_list) do
new_text_list =
text_list
|> Enum.map(fn string ->
string
|> String.split(~r/#{head}/, include_captures: true)
end)
|> List.flatten
split_on_emoticons(tail, new_text_list)
end
defp split_on_emoticons([], text_list) do
text_list
end
end