sentiment_agent.rb 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. require 'csv'
  2. module Agents
  3. class SentimentAgent < Agent
  4. class_attribute :anew
  5. cannot_be_scheduled!
  6. description <<~MD
  7. The Sentiment Agent generates `good-bad` (psychological valence or happiness index), `active-passive` (arousal), and `strong-weak` (dominance) score. It will output a value between 1 and 9. It will only work on English content.
  8. Make sure the content this agent is analyzing is of sufficient length to get respectable results.
  9. Provide a JSONPath in `content` field where content is residing and set `expected_receive_period_in_days` to the maximum number of days you would allow to be passed between events being received by this agent.
  10. MD
  11. event_description <<~MD
  12. Events look like:
  13. {
  14. "content": "The quick brown fox jumps over the lazy dog.",
  15. "valence": 6.196666666666666,
  16. "arousal": 4.993333333333333,
  17. "dominance": 5.63
  18. }
  19. MD
  20. def default_options
  21. {
  22. 'content' => "$.message.text[*]",
  23. 'expected_receive_period_in_days' => 1
  24. }
  25. end
  26. def working?
  27. last_receive_at && last_receive_at > interpolated['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
  28. end
  29. def receive(incoming_events)
  30. anew = self.class.sentiment_hash
  31. incoming_events.each do |event|
  32. Utils.values_at(event.payload, interpolated['content']).each do |content|
  33. sent_values = sentiment_values anew, content
  34. create_event payload: {
  35. 'content' => content,
  36. 'valence' => sent_values[0],
  37. 'arousal' => sent_values[1],
  38. 'dominance' => sent_values[2],
  39. 'original_event' => event.payload
  40. }
  41. end
  42. end
  43. end
  44. def validate_options
  45. errors.add(
  46. :base,
  47. "content and expected_receive_period_in_days must be present"
  48. ) unless options['content'].present? && options['expected_receive_period_in_days'].present?
  49. end
  50. def self.sentiment_hash
  51. unless self.anew
  52. self.anew = {}
  53. CSV.foreach Rails.root.join('data/anew.csv') do |row|
  54. self.anew[row[0]] = row.values_at(2, 4, 6).map { |val| val.to_f }
  55. end
  56. end
  57. self.anew
  58. end
  59. def sentiment_values(anew, text)
  60. valence, arousal, dominance, freq = [0] * 4
  61. text.downcase.strip.gsub(/[^a-z ]/, "").split.each do |word|
  62. next unless anew.has_key? word
  63. valence += anew[word][0]
  64. arousal += anew[word][1]
  65. dominance += anew[word][2]
  66. freq += 1
  67. end
  68. if valence != 0
  69. [valence / freq, arousal / freq, dominance / freq]
  70. else
  71. ["Insufficient data for meaningful answer"] * 3
  72. end
  73. end
  74. end
  75. end