Packages

Sentiment analysis based on afinn-165, emojis and some enhancements.

Current section

Files

Jump to
veritaserum lib veritaserum.ex
Raw

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(String.t()) | String.t()) :: list(integer) | integer
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(), return: :score_and_marks) :: {number(), [{atom, number, String.t()}]}
def analyze(input, return: :score_and_marks) do
list_with_marks = get_list_with_marks(input)
score = get_score(list_with_marks)
{score, list_with_marks}
end
def analyze(input) do
{score, _} = analyze(input, return: :score_and_marks)
score
end
defp get_score(words) do
words
|> analyze_list
|> Enum.sum()
end
defp get_list_with_marks(input) do
input
|> clean
|> String.split()
|> mark_list
|> Enum.reverse()
end
defp mark_word(word) do
with {_, nil, _} <- {:negator, Evaluator.evaluate_negator(word), word},
{_, nil, _} <- {:booster, Evaluator.evaluate_booster(word), word},
{_, nil, _} <- {:emoticon, Evaluator.evaluate_emoticon(word), word},
{_, nil, _} <- {:word, Evaluator.evaluate_word(word), word},
do: {:neutral, 0, word}
end
defp mark_list([head | tail]) do
mark_list(tail, [mark_word(head)])
end
defp mark_list([head | tail], result) do
mark_list(tail, [mark_word(head) | result])
end
defp mark_list([], result), do: result
defp analyze_mark({type, score, _}) do
case type do
:word -> score
:emoticon -> score
_ -> 0
end
end
defp analyze_mark(mark, previous) do
case previous do
{:negator, _, _} ->
-analyze_mark(mark)
{:booster, booster_value, _} ->
analyze_mark(mark) |> apply_booster(booster_value)
_ ->
analyze_mark(mark)
end
end
defp analyze_list([head | tail]) do
analyze_list(tail, head, [analyze_mark(head)])
end
defp analyze_list([head | tail], previous, result) do
analyze_list(tail, head, [analyze_mark(head, previous) | result])
end
defp analyze_list([], _, result), do: result
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(Evaluator.emoticon_list(), " ", insert_replaced: 1)
|> String.replace(~r/ {2,}/, " ")
end
end