Module: Legion::Extensions::Privatecore::Helpers::NerClient

Defined in:
lib/legion/extensions/privatecore/helpers/ner_client.rb

Defined Under Namespace

Classes: NerServiceUnavailable

Constant Summary collapse

ENTITY_MAP =
{
  'EMAIL_ADDRESS'     => :email,
  'PHONE_NUMBER'      => :phone,
  'US_SSN'            => :ssn,
  'IP_ADDRESS'        => :ip,
  'CREDIT_CARD'       => :credit_card,
  'DATE_TIME'         => :dob,
  'MEDICAL_LICENSE'   => :mrn,
  'PERSON'            => :person_name,
  'ORGANIZATION'      => :organization,
  'LOCATION'          => :location,
  'IBAN_CODE'         => :iban,
  'US_PASSPORT'       => :passport,
  'US_DRIVER_LICENSE' => :drivers_license,
  'CRYPTO'            => :crypto,
  'NRP'               => :national_id
}.freeze
NER_CATEGORIES =
{
  person_name:  :personal,
  organization: :entity,
  location:     :location,
  national_id:  :government_id,
  crypto:       :crypto
}.freeze

Class Method Summary collapse

Class Method Details

.analyze(text:, connection:, fallback: :transparent, timeout: 5) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
# File 'lib/legion/extensions/privatecore/helpers/ner_client.rb', line 41

def analyze(text:, connection:, fallback: :transparent, timeout: 5)
  response = connection.post do |req|
    req.headers['Content-Type'] = 'application/json'
    req.body = ::JSON.generate(text: text, language: 'en')
    req.options.timeout = timeout
  end

  parse_response(response, text)
rescue Faraday::Error, ::JSON::ParserError => e
  handle_fallback(fallback, e)
end

.available?(connection:) ⇒ Boolean

Returns:

  • (Boolean)


53
54
55
56
57
58
59
# File 'lib/legion/extensions/privatecore/helpers/ner_client.rb', line 53

def available?(connection:)
  response = connection.get('/health')
  response.status == 200
rescue Faraday::Error => e
  Legion::Logging.warn "[privatecore] NER health check failed: #{e.message}" # rubocop:disable Legion/HelperMigration/DirectLogging
  false
end

.build_connection(service_url:, timeout: 5) ⇒ Object



61
62
63
64
65
66
67
68
# File 'lib/legion/extensions/privatecore/helpers/ner_client.rb', line 61

def build_connection(service_url:, timeout: 5)
  require 'faraday'
  Faraday.new(url: service_url) do |f|
    f.options.timeout = timeout
    f.options.open_timeout = timeout
    f.adapter Faraday.default_adapter
  end
end

.handle_fallback(fallback, error) ⇒ Object



99
100
101
102
103
104
105
106
107
108
# File 'lib/legion/extensions/privatecore/helpers/ner_client.rb', line 99

def handle_fallback(fallback, error)
  case fallback
  when :transparent
    { fallback: true, detections: [] }
  when :strict
    raise NerServiceUnavailable, "NER service unavailable: #{error.message}"
  else
    []
  end
end

.parse_response(response, text) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/legion/extensions/privatecore/helpers/ner_client.rb', line 70

def parse_response(response, text)
  return [] unless response.status == 200

  entities = ::JSON.parse(response.body)
  entities.filter_map do |entity|
    type = ENTITY_MAP[entity['entity_type']]
    next unless type

    category = NER_CATEGORIES[type]
    if category.nil?
      begin
        category = Patterns::PATTERNS.dig(type, :category) || :unknown
      rescue NameError => _e
        category = :unknown
      end
    end

    {
      type:     type,
      category: category,
      start:    entity['start'],
      end:      entity['end'],
      match:    text[entity['start']...entity['end']],
      score:    entity['score'],
      source:   :ner
    }
  end
end