Commit 1af3d203 authored by alexlag's avatar alexlag
Browse files

some style fixes

parent 55d227bb
......@@ -3,16 +3,16 @@ require 'rake/testtask'
Rake::TestTask.new do |t|
t.name = 'test:texterra'
t.libs << 'test'
t.test_files = ['test/test_texterra_api.rb']
t.test_files = ['test/test_texterra_api.rb']
end
Rake::TestTask.new do |t|
t.name = 'test:twitter'
t.libs << 'test'
t.test_files = ['test/test_twitter_api.rb']
t.test_files = ['test/test_twitter_api.rb']
end
task :test => ['test:texterra', 'test:twitter']
task test: ['test:texterra', 'test:twitter']
desc "Run all tests"
task :default => :test
\ No newline at end of file
desc 'Run all tests'
task default: :test
require "./lib/ispras-api/version"
require './lib/ispras-api/version'
Gem::Specification.new do |s|
s.name = 'ispras-api'
s.version = Version.current
s.date = Version.current_date
s.files = `git ls-files`.split($\)
s.require_paths = ["lib"]
s.require_paths = ['lib']
s.add_runtime_dependency 'httparty', '~> 0.13'
s.add_runtime_dependency 'nori', '~> 2.4'
s.add_development_dependency 'rake', '~> 10.4'
s.add_development_dependency 'minitest', '~> 5.5'
s.add_development_dependency 'dotenv', '~> 1.0'
s.summary = "ISPRAS API Ruby SDK"
s.description = "This is Ruby wrapper for REST API provided by ISPRAS. More info at https://api.ispras.ru/"
s.homepage = "https://github.com/alexlag/ispapi.ruby"
s.authors = ["Alexey Laguta"]
s.summary = 'ISPRAS API Ruby SDK'
s.description = 'This is Ruby wrapper for REST API provided by ISPRAS. More info at https://api.ispras.ru/'
s.homepage = 'https://github.com/alexlag/ispapi.ruby'
s.authors = ['Alexey Laguta']
s.email = 'laguta@ispras.ru'
end
\ No newline at end of file
end
require_relative 'ispras-api/texterra_api'
\ No newline at end of file
require_relative 'ispras-api/texterra_api'
ApiError = Class.new StandardError
\ No newline at end of file
ApiError = Class.new StandardError
......@@ -12,26 +12,25 @@ class IsprasAPI
self.class.base_uri ROOT_URL % [name, ver]
self.class.default_params apikey: key
else
raise ApiError, 'Please provide proper apikey'
fail ApiError, 'Please provide proper apikey'
end
end
def GET(path='', params={})
def GET(path = '', params = {})
options = { query: params }
response = self.class.get "/#{path}", options
response.code == 200 ? response.parsed_response : check_error(response)
end
def POST(path='', params={}, form={})
def POST(path = '', params = {}, form = {})
options = { query: params, body: form }
response = self.class.post "/#{path}", options
response.code == 200 ? response.parsed_response : check_error(response)
end
private
private
def check_error(response)
raise ApiError, "#{response.code} Error occured"
end
end
\ No newline at end of file
def check_error(response)
fail ApiError, "#{response.code} Error occured"
end
end
......@@ -8,38 +8,42 @@ module TexterraKBM
# @param term [String] term
# @return [Hash] with :presence field
def term_presence(term)
presetKBM :termPresence, term
preset_kbm :termPresence, term
end
# Returns information measure for the given term. Information measure denotes, how often given term is used as link caption among all its occurences
# Returns information measure for the given term. Information measure denotes,
# how often given term is used as link caption among all its occurences
#
# @param term [String] term
# @result [Hash] with :infomeasure field
def term_info_measure(term)
presetKBM :termInfoMeasure, term
preset_kbm :termInfoMeasure, term
end
# Return concepts resource from the Knowledge base corresponding to the found meanings of the given term
# Return concepts resource from the Knowledge base corresponding
# to the found meanings of the given term
#
# @param term [String] term
# @result [Hash] with :elements field
def term_meanings(term)
presetKBM :termMeanings, term
preset_kbm :termMeanings, term
end
# If concept isn't provided, returns concepts with their commonness, corresponding to the found meanings of the given term. Commonness denotes, how often the given term is associated with the given concept.
# If concept isn't provided, returns concepts with their commonness,
# corresponding to the found meanings of the given term.
# Commonness denotes, how often the given term is associated with the given concept.
# With concept(format is {id}:{kbname}) returns commonness of given concept for the given term.
#
# @param term [String] term
# @param concept [String] concept as {id}:{kbname}
# @result [Hash] with :elements field
def term_commonness(term, concept='')
def term_commonness(term, concept = '')
concept = "id=#{concept}" unless concept.empty?
presetKBM :termCommonness, [term, concept]
preset_kbm :termCommonness, [term, concept]
end
# Return neighbour concepts for the given concepts(list or single concept, each concept is {id}:{kbname}).
#
# Return neighbour concepts for the given concepts(list or single concept, each concept is {id}:{kbname}).
#
# @param concepts [String, Array<String>] either concept as {id}:{kbname} or array of such concepts
# @param traverse_params [Hash] optional
# @option traverse_params [String] :linkType searching for neightbour concepts only along these link types
......@@ -48,17 +52,17 @@ module TexterraKBM
# @option traverse_params [Fixnum] :maxDepth maximum distance from original to result concepts
#
# @result [Hash] with :elements field
#
# If at least one traverse parameter(check REST Documentation for values) is specified, all other parameters should also be specified
def neighbours(concepts, traverse_params={})
#
# If at least one traverse parameter(check REST Documentation for values) is specified, all other parameters should also be specified
def neighbours(concepts, traverse_params = {})
traverse = traverse_params.inject('') do |res, (name, value)|
res += ";#{name}=#{value}"
res + ";#{name}=#{value}"
end unless traverse_params.empty?
presetKBM :neighbours, [wrap_concepts(concepts), traverse]
preset_kbm :neighbours, [wrap_concepts(concepts), traverse]
end
# Return neighbour concepts size for the given concepts(list or single concept, each concept is {id}:{kbname}).
#
#
# @param concepts [String, Array<String>] either concept as {id}:{kbname} or array of such concepts
# @param traverse_params [Hash] optional
# @option traverse_params [String] :linkType searching for neightbour concepts only along these link types
......@@ -67,104 +71,103 @@ module TexterraKBM
# @option traverse_params [Fixnum] :maxDepth maximum distance from original to result concepts
#
# @result [Hash] with :size field
#
# @note If at least one traverse parameter(check REST Documentation for values) is specified, all other parameters should also be specified
def neighbours_size(concepts, traverse_params={})
#
# @note If at least one traverse parameter(check REST Documentation for values) is specified, all other parameters should also be specified
def neighbours_size(concepts, traverse_params = {})
traverse = traverse_params.inject('') do |res, (name, value)|
res += ";#{name}=#{value}"
res + ";#{name}=#{value}"
end unless traverse_params.empty?
presetKBM :neighbours, [wrap_concepts(concepts), "#{traverse}/size"]
preset_kbm :neighbours, [wrap_concepts(concepts), "#{traverse}/size"]
end
# Compute similarity for each pair of concepts(list or single concept, each concept is {id}:{kbname}).
# Compute similarity for each pair of concepts(list or single concept, each concept is {id}:{kbname}).
#
# @param [Array<String>] concepts Array of concepts as {id}:{kbname}
# @param [String] linkWeight Specifies method for computation of link weight in case of multiple link types - check REST Documentation for values
def similarity_graph(concepts, linkWeight='MAX')
presetKBM :similarityGraph, "#{wrap_concepts(concepts)}linkWeight=#{linkWeight}"
def similarity_graph(concepts, linkWeight = 'MAX')
preset_kbm :similarityGraph, "#{wrap_concepts(concepts)}linkWeight=#{linkWeight}"
end
# Computes sum of similarities from each concepts(list or single concept, each concept is {id}:{kbname}) from the first list to all concepts(list or single concept, each concept is {id}:{kbname}) from the second one.
#
#
# @param [Array<String>] first_concepts Array of concepts as {id}:{kbname}
# @param [Array<String>] second_concepts Array of concepts as {id}:{kbname}
# @param [String] linkWeight Specifies method for computation of link weight in case of multiple link types - check REST Documentation for values
def all_pairs_similarity(first_concepts, second_concepts, linkWeight='MAX')
presetKBM :allPairsSimilarity, ["#{wrap_concepts(first_concepts)}linkWeight=#{linkWeight}", wrap_concepts(second_concepts)]
# @param [String] linkWeight Specifies method for computation of link weight in case of multiple link types - check REST Documentation for values
def all_pairs_similarity(first_concepts, second_concepts, linkWeight = 'MAX')
preset_kbm :allPairsSimilarity, ["#{wrap_concepts(first_concepts)}linkWeight=#{linkWeight}", wrap_concepts(second_concepts)]
end
# Compute similarity from each concept from the first list to all concepts(list or single concept, each concept is {id}:{kbname}) from the second list as a whole.
# Links of second list concepts(each concept is {id}:{kbname}) are collected together, thus forming a "virtual" article, similarity to which is computed.
#
#
# @param [Array<String>] concepts Array of concepts as {id}:{kbname}
# @param [Array<String>] virtual_aricle Array of concepts as {id}:{kbname}
# @param [String] linkWeight Specifies method for computation of link weight in case of multiple link types - check REST Documentation for values
def similarity_to_virtual_article(concepts, virtual_aricle, linkWeight='MAX')
presetKBM :similarityToVirtualArticle, ["#{wrap_concepts(concepts)}linkWeight=#{linkWeight}", wrap_concepts(virtual_aricle)]
# @param [String] linkWeight Specifies method for computation of link weight in case of multiple link types - check REST Documentation for values
def similarity_to_virtual_article(concepts, virtual_aricle, linkWeight = 'MAX')
preset_kbm :similarityToVirtualArticle, ["#{wrap_concepts(concepts)}linkWeight=#{linkWeight}", wrap_concepts(virtual_aricle)]
end
# Compute similarity between two sets of concepts(list or single concept, each concept is {id}:{kbname}) as between "virtual" articles from these sets.
# The links of each virtual article are composed of links of the collection of concepts.
#
# The links of each virtual article are composed of links of the collection of concepts.
#
# @param [Array<String>] first_virtual_aricle Array of concepts as {id}:{kbname}
# @param [Array<String>] second_virtual_article Array of concepts as {id}:{kbname}
# @param [String] linkWeight Specifies method for computation of link weight in case of multiple link types - check REST Documentation for values
def similarity_between_virtual_articles(first_virtual_aricle, second_virtual_article, linkWeight='MAX')
presetKBM :similarityBetweenVirtualArticle, ["#{wrap_concepts(first_virtual_aricle)}linkWeight=#{linkWeight}", wrap_concepts(second_virtual_article)]
# @param [String] linkWeight Specifies method for computation of link weight in case of multiple link types - check REST Documentation for values
def similarity_between_virtual_articles(first_virtual_aricle, second_virtual_article, linkWeight = 'MAX')
preset_kbm :similarityBetweenVirtualArticle, ["#{wrap_concepts(first_virtual_aricle)}linkWeight=#{linkWeight}", wrap_concepts(second_virtual_article)]
end
# Search for similar concepts among the first neighbours of the given ones(list or single concept, each concept is {id}:{kbname}).
#
#
# @param [Array<String>] concepts Array of concepts as {id}:{kbname}
# @param [Hash] params
# @option params [String] :linkWeight Specifies method for computation of link weight in case of multiple link types
# @param [Hash] params
# @option params [String] :linkWeight Specifies method for computation of link weight in case of multiple link types
# @option params [Fixnum] :offset Provides a possibility to skip several concepts from the start of the result
# @option params [Fixnum] :limit Provides a possibility to limit size of result
#
#
# @note check REST Documentation for values
def similar_over_first_neighbours(concepts, params={linkWeight:'MAX'})
presetKBM :similarOverFirstNeighbours, "#{wrap_concepts(concepts)};linkWeight=#{params[:linkWeight]}", params
def similar_over_first_neighbours(concepts, params = { linkWeight: 'MAX' })
preset_kbm :similarOverFirstNeighbours, "#{wrap_concepts(concepts)};linkWeight=#{params[:linkWeight]}", params
end
# Search for similar concepts over filtered set of the first and the second neighbours of the given ones(list or single concept, each concept is {id}:{kbname}).
#
#
# @param [Array<String>] concepts Array of concepts as {id}:{kbname}
# @param [Hash] params
# @option params [String] :linkWeight Specifies method for computation of link weight in case of multiple link types
# @option params [Fixnum] :offset Provides a possibility to skip several concepts from the start of the result
# @option params [Fixnum] :limit Provides a possibility to limit size of result
# @param [Hash] params
# @option params [String] :linkWeight Specifies method for computation of link weight in case of multiple link types
# @option params [Fixnum] :offset Provides a possibility to skip several concepts from the start of the result
# @option params [Fixnum] :limit Provides a possibility to limit size of result
# @option params [String] :among Specifies how to filter neighbour concepts when searching for most similar
#
#
# @note check REST Documentation for values
def similar_over_filtered_neighbours(concepts, params={linkWeight:'MAX'})
presetKBM :similarOverFilteredNeighbours, "#{wrap_concepts(concepts)};linkWeight=#{params[:linkWeight]}", params
def similar_over_filtered_neighbours(concepts, params = { linkWeight: 'MAX' })
preset_kbm :similarOverFilteredNeighbours, "#{wrap_concepts(concepts)};linkWeight=#{params[:linkWeight]}", params
end
# Get attributes for concepts(list or single concept, each concept is {id}:{kbname})
#
#
# @param [String, Array<String>] concepts Either concept as {id}:{kbname} or array of such concepts
# @param [Array<String>] attributes Specifies attributes to be included into response
# @note check REST Documentation for supported attributes
def get_attributes(concepts, attributes=[])
presetKBM :getAttributes, wrap_concepts(concepts), attribute: attributes
def get_attributes(concepts, attributes = [])
preset_kbm :getAttributes, wrap_concepts(concepts), attribute: attributes
end
private
# Utility wrapper for matrix parameters
def wrap_concepts(concepts)
if concepts.is_a? Array
concepts.map { |c| "id=#{c};" }.join
else
"id=#{concepts};"
end
end
private
# Utility EKB part method
def presetKBM(methodName, pathParam, queryParam={})
specs = KBMSpecs[methodName]
queryParam.merge specs[:params]
GET(specs[:path] % pathParam, queryParam)
# Utility wrapper for matrix parameters
def wrap_concepts(concepts)
if concepts.is_a? Array
concepts.map { |c| "id=#{c};" }.join
else
"id=#{concepts};"
end
end
end
\ No newline at end of file
# Utility EKB part method
def preset_kbm(methodName, pathParam, queryParam = {})
specs = KBM_SPECS[methodName]
queryParam.merge specs[:params]
GET(specs[:path] % pathParam, queryParam)
end
end
module TexterraKBMSpecs
# Path and parameters for preset KBM queries
KBMSpecs = {
KBM_SPECS = {
termPresence: {
path: 'representation/%s/contained',
params: {}
......@@ -50,4 +50,4 @@ module TexterraKBMSpecs
params: {}
}
}
end
\ No newline at end of file
end
......@@ -3,126 +3,126 @@ require_relative './nlp_specs'
module TexterraNLP
include TexterraNLPSpecs
# Detects language of given text
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def language_detection_annotate(text)
presetNLP(:languageDetection, text)
preset_nlp(:languageDetection, text)
end
# Detects boundaries of sentences in a given text
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def sentence_detection_annotate(text)
presetNLP(:sentenceDetection, text)
preset_nlp(:sentenceDetection, text)
end
# Detects all tokens (minimal significant text parts) in a given text
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def tokenization_annotate(text)
presetNLP(:tokenization, text)
preset_nlp(:tokenization, text)
end
# Detects lemma of each word of a given text
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def lemmatization_annotate(text)
presetNLP(:lemmatization, text)
preset_nlp(:lemmatization, text)
end
# Detects part of speech tag for each word of a given text
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def pos_tagging_annotate(text)
presetNLP(:posTagging, text)
preset_nlp(:posTagging, text)
end
# Tries to correct disprints and other spelling errors in a given text
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def spelling_correction_annotate(text)
presetNLP(:spellingCorrection, text)
preset_nlp(:spellingCorrection, text)
end
# Finds all named entities occurences in a given text
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def named_entities_annotate(text)
presetNLP(:namedEntities, text)
preset_nlp(:namedEntities, text)
end
# Extracts not overlapping terms within a given text; term is a textual representation for some concept of the real world
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def term_detection_annotate(text)
presetNLP(:termDetection, text)
preset_nlp(:termDetection, text)
end
# Detects the most appropriate meanings (concepts) for terms occurred in a given text
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def disambiguation_annotate(text)
presetNLP(:disambiguation, text)
preset_nlp(:disambiguation, text)
end
# Key concepts are the concepts providing short (conceptual) and informative text description.
# This service extracts a set of key concepts for a given text
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def key_concepts_annotate(text)
presetNLP(:keyConcepts, text)
preset_nlp(:keyConcepts, text)
end
# Detects the most appropriate domain for the given text.
# Currently only 2 specific domains are supported: 'movie' and 'politics'
# If no domain from this list has been detected, the text is assumed to be no domain, or general domain
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def domain_detection_annotate(text)
presetNLP(:domainDetection, text)
preset_nlp(:domainDetection, text)
end
# Detects whether the given text is subjective or not
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def subjectivity_detection_annotate(text)
presetNLP(:subjectivityDetection, text)
preset_nlp(:subjectivityDetection, text)
end
# Detects whether the given text has positive, negative or no sentiment
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def polarity_detection_annotate(text)
presetNLP(:polarityDetection, text)
preset_nlp(:polarityDetection, text)
end
# Detects whether the given text has positive, negative, or no sentiment, with respect to domain.
# Detects whether the given text has positive, negative, or no sentiment, with respect to domain.
# If domain isn't provided, Domain detection is applied, this way method tries to achieve best results.
# If no domain is detected general domain algorithm is applied
#
#
# @param [String] text Text to process
# @param [String] domain Domain for polarity detection
# @return [Array] Texterra annotations
def domain_polarity_detection_annotate(text, domain='')
specs = NLPSpecs[:domainPolarityDetection]
domain = '(%s)' % domain unless domain.empty?
result = POST(specs[:path] % domain, specs[:params], {text: text})[:nlp_document][:annotations][:i_annotation]
def domain_polarity_detection_annotate(text, domain = '')
specs = NLP_SPECS[:domainPolarityDetection]
domain = "(#{domain})" unless domain.empty?
result = POST(specs[:path] % domain, specs[:params], text: text)[:nlp_document][:annotations][:i_annotation]
return [] if result.nil?
result = [].push result unless result.is_a? Array
result.each do |e|
result.each do |e|
st, en = e[:start].to_i, e[:end].to_i
e[:text] = e[:annotated_text] = text[st..en]
end
......@@ -130,24 +130,24 @@ module TexterraNLP
# Detects Twitter-specific entities: Hashtags, User names, Emoticons, URLs.
# And also: Stop-words, Misspellings, Spelling suggestions, Spelling corrections
#
#
# @param [String] text Text to process
# @return [Array] Texterra annotations
def tweet_normalization(text)
presetNLP(:tweetNormalization, text)
preset_nlp(:tweetNormalization, text)
end
private
# Utility NLP part method
def presetNLP(methodName, text)
specs = NLPSpecs[methodName]
result = POST(specs[:path], specs[:params], {text: text})[:nlp_document][:annotations][:i_annotation]
return [] if result.nil?
result = [].push result unless result.is_a? Array
result.each do |e|
st, en = e[:start].to_i, e[:end].to_i
e[:text] = e[:annotated_text] = text[st..en]
end
# Utility NLP part method
def preset_nlp(methodName, text)
specs = NLP_SPECS[methodName]
result = POST(specs[:path], specs[:params], text: text)[:nlp_document][:annotations][:i_annotation]
return [] if result.nil?
result = [].push result unless result.is_a? Array
result.each do |e|
st, en = e[:start].to_i, e[:end].to_i
e[:text] = e[:annotated_text] = text[st..en]
end
end
\ No newline at end of file
end
end
module TexterraNLPSpecs
# Path and parameters for preset NLP queries
NLPSpecs = {
NLP_SPECS = {
languageDetection: {
path: 'nlp/ru.ispras.texterra.core.nlp.pipelines.LanguageDetectionPipeline',
params: {
:class => 'ru.ispras.texterra.core.nlp.datamodel.Language',
filtering: 'KEEPING'
}
path: 'nlp/ru.ispras.texterra.core.nlp.pipelines.LanguageDetectionPipeline',
params: {
class: 'ru.ispras.texterra.core.nlp.datamodel.Language',
filtering: 'KEEPING'
}
},
sentenceDetection: {
path: 'nlp/sentence',
params: {
:class => 'ru.ispras.texterra.core.nlp.datamodel.Sentence',
filtering: 'KEEPING'
}
path: 'nlp/sentence',
params: {
class: 'ru.ispras.texterra.core.nlp.datamodel.Sentence',
filtering: 'KEEPING'
}
},
tokenization: {
path: 'nlp/token',
params: {
:class => 'ru.ispras.texterra.core.nlp.datamodel.Token',
filtering: 'KEEPING'
}
path: 'nlp/token',
params: {
class: 'ru.ispras.texterra.core.nlp.datamodel.Token',
filtering: 'KEEPING'
}
},
lemmatization: {
path: 'nlp/lemma',
params: {
:class => 'ru.ispras.texterra.core.nlp.datamodel.Lemma',
filtering: 'KEEPING'
}
path: 'nlp/lemma',
params: {
class: 'ru.ispras.texterra.core.nlp.datamodel.Lemma',
filtering: 'KEEPING'
}
},
posTagging: {
path: 'nlp/pos',
params: {
:class => 'ru.ispras.texterra.core.nlp.datamodel.pos.POSToken',
filtering: 'KEEPING'
}
path: 'nlp/pos',
params: {
class: 'ru.ispras.texterra.core.nlp.datamodel.pos.POSToken',
filtering: 'KEEPING'
}
},
spellingCorrection: {
path: 'nlp/ru.ispras.texterra.core.nlp.annotators.spelling.SpellingCorrector',
params: {
:class => 'ru.ispras.texterra.core.nlp.datamodel.SpellingCorrection',