tangram 0.1.0.pre.alpha.7 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c4cbfd5a24c6561fe11c81ae785d47bc4f4e16a0b11c10f079c63d863c6cb15
4
- data.tar.gz: 29d6160096b0ca3d692781d07f4dffb971ab9563c9a6bd1c7911a1676e161806
3
+ metadata.gz: e622eeb9d9cd659b75acbf6dc167a0685a5111ab35a434c888c497de99faf742
4
+ data.tar.gz: 91c21be6670a9e3d3072648dba57b570a4cc313958af8a5a16ee7588f461c9b9
5
5
  SHA512:
6
- metadata.gz: d8e03fe9d77eedf28dc4ab6b6cbf17f6c5274479b1a0324f7071d5e5f608a0fc17bb312b46d995c6873b8b7ef8fac81f8b02490ca06038e936c61a07ac19f38b
7
- data.tar.gz: 8c47ffbf42a08c613e3e6bcfdcefc396d5db0d2288a85b52f3bf766f30f9a0bff685d04c282a837b693e2c959e4037713f655a3e07a01e4fe1bc04077ee997df
6
+ metadata.gz: 5079553215b584e04826f4e522e5b47587711e7493c389f587ec2202acc33a72a9f769d1155e11f746bbb69320a4d2a3bee587701b33877a558ddf467d7d967c
7
+ data.tar.gz: 0d86be9c1a11e988cbcd6549ae9eb55c0cde9126ab85f1f99f23f796100c158ee32401fe92e0a63b28bacee114cf3a15f2cf0af6b265bf3dbd03717ed44bd86d
data/README.md CHANGED
@@ -1 +1,52 @@
1
- # tangram-ruby
1
+ # Tangram + Ruby
2
+
3
+ - [Watch the Video](https://www.tangramhq.com)
4
+ - [Follow the Getting Started guide](https://www.tangramhq.com/docs/getting-started)
5
+
6
+ The Tangram Ruby library makes it easy to make predictions with your Tangram machine learning model from Ruby.
7
+
8
+ ## Usage
9
+
10
+ ```
11
+ $ gem install tangram
12
+ ```
13
+
14
+ ```ruby
15
+ require 'tangram'
16
+
17
+ model = Tangram::Model.from_file('./heart-disease.tangram')
18
+
19
+ input = {
20
+ age: 63,
21
+ gender: 'male',
22
+ # ...
23
+ }
24
+
25
+ output = model.predict(input)
26
+
27
+ puts(output)
28
+ ```
29
+
30
+ For more information, follow the [Getting Started guide](https://www.tangramhq.com/docs/getting-started).
31
+
32
+ ## Examples
33
+
34
+ This repo contains two examples, [examples/predict]([examples/predict]) and [examples/monitor](examples/monitor).
35
+
36
+ ### Predict
37
+
38
+ This example demonstrates loading a model from a `.tangram` file and making a prediction.
39
+
40
+ ### Monitor
41
+
42
+ This example demonstrates logging predictions and true values to the Tangram reporting and monitoring app. Before running the example, upload the `heart-disease.tangram` file in [examples/monitor/heart-disease.tangram](examples/monitor/heart-disease.tangram) to either https://app.tangramhq.com or your private instance. Then generate a token by clicking the "Tokens" link on the right side of the top bar.
43
+
44
+ Then you can run the example:
45
+
46
+ ```
47
+ $ TANGRAM_TOKEN=<YOUR TOKEN HERE> ruby examples/monitor/main.rb
48
+ ```
49
+
50
+ Now if you refresh the production stats or production metrics tabs for the model you uploaded, you should see predictions and true values being reported.
51
+
52
+ For more information on reporting and monitoring, follow the [Getting Started guide](https://www.tangramhq.com/docs/getting-started).
@@ -0,0 +1,52 @@
1
+ require 'tangram'
2
+
3
+ # Go to https://app.tangramhq.com or your private instance, upload the `heart-disease.tangram` file adjacent to this file, generate a token, and pass it as an environment variable to this script.
4
+ token = ENV['TANGRAM_TOKEN']
5
+ if token.nil?
6
+ raise 'TANGRAM_TOKEN environment variable not set'
7
+ end
8
+ base_url = ENV['TANGRAM_BASE_URL'] || 'https://app.tangramhq.com'
9
+
10
+ # Get the path to the `.tangram` file.
11
+ model_path = File.join(File.dirname(__FILE__), 'heart-disease.tangram')
12
+ # Load the model from the file and set the Tangram API token and base url.
13
+ model = Tangram::Model.from_file(model_path, token: token, base_url: base_url)
14
+
15
+ # Create an example input matching the schema of the CSV file the model was trained on. Here the data is just hard-coded, but in your application you will probably get this from a database or user input.
16
+ input = {
17
+ age: 63,
18
+ gender: 'male',
19
+ chest_pain: 'typical angina',
20
+ resting_blood_pressure: 145,
21
+ cholesterol: 233,
22
+ fasting_blood_sugar_greater_than_120: 'true',
23
+ resting_ecg_result: 'probable or definite left ventricular hypertrophy',
24
+ exercise_max_heart_rate: 150,
25
+ exercise_induced_angina: 'no',
26
+ exercise_st_depression: 2.3,
27
+ exercise_st_slope: 'downsloping',
28
+ fluoroscopy_vessels_colored: 0,
29
+ thallium_stress_test: 'fixed defect',
30
+ }
31
+
32
+ # Make the prediction using a custom threshold chosen on the "Tuning" page of the Tangram reporting and monitoring app.
33
+ options = { threshold: 0.25 }
34
+ output = model.predict(input, options: options)
35
+
36
+ # Make the prediction using a custom threshold chosen on the "Tuning" page of the Tangram reporting and monitoring app.
37
+ puts('Input:', input)
38
+ puts('Output:', output)
39
+
40
+ # Log the prediction. This will allow us to view production stats in the Tangram reporting and monitoring app.
41
+ model.log_prediction(
42
+ identifier: 'John Doe',
43
+ options: options,
44
+ input: input,
45
+ output: output,
46
+ )
47
+
48
+ # Later on, if we get an official diagnosis for the patient, we can log the true value for the prior prediction. Make sure to match the `identifier` from the former prediction.
49
+ model.log_true_value(
50
+ identifier: 'John Doe',
51
+ true_value: 'Positive',
52
+ )
@@ -0,0 +1,30 @@
1
+ require 'tangram'
2
+
3
+ # Get the path to the .tangram file.
4
+ model_path = File.join(File.dirname(__FILE__), 'heart-disease.tangram')
5
+ # Load the model from the file.
6
+ model = Tangram::Model.from_file(model_path)
7
+
8
+ # Create an example input matching the schema of the CSV file the model was trained on. Here the data is just hard-coded, but in your application you will probably get this from a database or user input.
9
+ input = {
10
+ age: 63,
11
+ gender: 'male',
12
+ chest_pain: 'typical angina',
13
+ resting_blood_pressure: 145,
14
+ cholesterol: 233,
15
+ fasting_blood_sugar_greater_than_120: 'true',
16
+ resting_ecg_result: 'probable or definite left ventricular hypertrophy',
17
+ exercise_max_heart_rate: 150,
18
+ exercise_induced_angina: 'no',
19
+ exercise_st_depression: 2.3,
20
+ exercise_st_slope: 'downsloping',
21
+ fluoroscopy_vessels_colored: 0,
22
+ thallium_stress_test: 'fixed defect',
23
+ }
24
+
25
+ # Make the prediction!
26
+ output = model.predict(input)
27
+
28
+ # Print out the input and output.
29
+ puts('Input:', input)
30
+ puts('Output:', output)
@@ -5,13 +5,13 @@ module LibTangram
5
5
  cpu = RbConfig::CONFIG['host_cpu']
6
6
  os = RbConfig::CONFIG['host_os']
7
7
  if cpu == 'x86_64' and os =~ /linux/
8
- library_name = 'libtangram-0.1.0-alpha.4-linux-x86_64.so'
8
+ library_name = 'libtangram-0.1.0-linux-x86_64.so'
9
9
  elsif cpu == 'x86_64' and os =~ /darwin/
10
- library_name = 'libtangram-0.1.0-alpha.4-macos-x86_64.dylib'
10
+ library_name = 'libtangram-0.1.0-macos-x86_64.dylib'
11
11
  elsif cpu == 'x86_64' and os =~ /mingw/
12
- library_name = 'tangram-0.1.0-alpha.4-windows-x86_64.dll'
12
+ library_name = 'tangram-0.1.0-windows-x86_64.dll'
13
13
  else
14
- raise 'tangram-ruby does not yet support your combination of operating system and CPU architecture.'
14
+ raise 'tangram-ruby does not yet support your combination of operating system and CPU architecture. Want support for your platform? Get in touch at help@tangramhq.com.'
15
15
  end
16
16
  extend FFI::Library
17
17
  ffi_lib File.expand_path("#{library_name}", __dir__)
data/lib/tangram/model.rb CHANGED
@@ -1,18 +1,23 @@
1
- require 'tangram/libtangram'
2
1
  require 'json'
2
+ require 'net/http'
3
+ require 'tangram/libtangram'
3
4
 
4
5
  module Tangram
5
6
  class Model
6
- def self.from_file(model_path)
7
+
8
+ def self.from_file(model_path, base_url: nil, token: nil)
7
9
  model_data = IO.binread(model_path)
8
- self.from_data(model_data)
10
+ self.from_data(model_data, base_url: base_url, token: token)
9
11
  end
10
12
 
11
- def self.from_data(model_data)
12
- self.new(model_data)
13
+ def self.from_data(model_data, base_url: nil, token: nil)
14
+ self.new(model_data, base_url: base_url, token: token)
13
15
  end
14
16
 
15
- def initialize(model_data)
17
+ def initialize(model_data, base_url: nil, token: nil)
18
+ @base_url = base_url.nil? ? 'https://app.tangramhq.com' : base_url
19
+ @token = token
20
+ @log_queue = []
16
21
  model_ptr = FFI::MemoryPointer.new(:pointer)
17
22
  result = LibTangram.tangram_model_load(model_data, model_data.size, model_ptr)
18
23
  if result != 0
@@ -21,7 +26,18 @@ module Tangram
21
26
  @model = FFI::AutoPointer.new(model_ptr.read_pointer, LibTangram.method(:tangram_model_free))
22
27
  end
23
28
 
24
- def task
29
+ def id()
30
+ id_ptr = FFI::MemoryPointer.new(:pointer)
31
+ result = LibTangram.tangram_model_id(@model, id_ptr)
32
+ if result != 0
33
+ raise 'tangram error'
34
+ end
35
+ id = id_ptr.read_pointer.read_string.force_encoding('utf-8')
36
+ LibTangram.tangram_string_free(id_ptr.read_pointer)
37
+ id
38
+ end
39
+
40
+ def task()
25
41
  task_ptr = FFI::MemoryPointer.new(:pointer)
26
42
  result = LibTangram.tangram_model_task(@model, task_ptr)
27
43
  if result != 0
@@ -32,7 +48,7 @@ module Tangram
32
48
  task
33
49
  end
34
50
 
35
- def predict(input, options)
51
+ def predict(input, options: nil)
36
52
  input = JSON.unparse(input)
37
53
  unless options.nil?
38
54
  options = JSON.unparse(options)
@@ -49,5 +65,73 @@ module Tangram
49
65
  LibTangram.tangram_string_free(output_ptr.read_pointer)
50
66
  output
51
67
  end
68
+
69
+ def log_prediction(identifier:, options: nil, input:, output:)
70
+ self.log_event({
71
+ type: 'prediction',
72
+ modelId: self.id,
73
+ identifier: identifier,
74
+ options: options,
75
+ input: input,
76
+ output: output,
77
+ })
78
+ end
79
+
80
+ def enqueue_log_prediction(identifier:, options: nil, input:, output:)
81
+ self.log_queue.push({
82
+ type: 'prediction',
83
+ modelId: self.id,
84
+ identifier: identifier,
85
+ options: options,
86
+ input: input,
87
+ output: output,
88
+ })
89
+ end
90
+
91
+ def log_true_value(identifier:, true_value:)
92
+ self.log_event({
93
+ type: 'true_value',
94
+ modelId: self.id,
95
+ identifier: identifier,
96
+ trueValue: true_value,
97
+ })
98
+ end
99
+
100
+ def enqueue_log_true_value(identifier:, true_value:)
101
+ self.log_queue.push({
102
+ type: 'true_value',
103
+ modelId: self.id,
104
+ identifier: identifier,
105
+ trueValue: true_value,
106
+ })
107
+ end
108
+
109
+ def flush_log_queue()
110
+ self.log_events(@log_queue)
111
+ @log_queue = []
112
+ end
113
+
114
+ def log_event(event)
115
+ self.log_events([event])
116
+ end
117
+
118
+ def log_events(events)
119
+ if @token.nil?
120
+ raise 'Tangram cannot log events without a token. Make sure to pass a token to the model constructor.'
121
+ end
122
+ headers = {
123
+ 'Content-Type': 'application/json',
124
+ 'Authorization': 'Bearer ' + @token,
125
+ }
126
+ uri = URI(@base_url + '/api/track')
127
+ http = Net::HTTP.new(uri.host, uri.port)
128
+ request = Net::HTTP::Post.new(uri.request_uri, headers)
129
+ request.body = events.to_json
130
+ response = http.request(request)
131
+ unless response.kind_of? Net::HTTPSuccess
132
+ raise response
133
+ end
134
+ end
135
+
52
136
  end
53
137
  end
data/tangram.gemspec CHANGED
@@ -1,7 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "tangram"
3
- s.version = "0.1.0-alpha.7"
4
- s.date = "2019-11-22"
3
+ s.version = "0.1.1"
5
4
  s.summary = "Tangram for Ruby"
6
5
  s.description = "Make predictions with a Tangram model from your Ruby app. Learn more at https://www.tangramhq.com/."
7
6
  s.authors = ["Tangram"]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tangram
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre.alpha.7
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tangram
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-22 00:00:00.000000000 Z
11
+ date: 2020-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -32,13 +32,16 @@ extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
34
  - README.md
35
- - examples/heart-disease/main.rb
35
+ - examples/monitor/heart-disease.tangram
36
+ - examples/monitor/main.rb
37
+ - examples/predict/heart-disease.tangram
38
+ - examples/predict/main.rb
36
39
  - lib/tangram.rb
37
- - lib/tangram/libtangram-0.1.0-alpha.4-linux-x86_64.so
38
- - lib/tangram/libtangram-0.1.0-alpha.4-macos-x86_64.dylib
40
+ - lib/tangram/libtangram-0.1.0-linux-x86_64.so
41
+ - lib/tangram/libtangram-0.1.0-macos-x86_64.dylib
39
42
  - lib/tangram/libtangram.rb
40
43
  - lib/tangram/model.rb
41
- - lib/tangram/tangram-0.1.0-alpha.4-windows-x86_64.dll
44
+ - lib/tangram/tangram-0.1.0-windows-x86_64.dll
42
45
  - scripts/build
43
46
  - tangram.gemspec
44
47
  homepage: http://rubygems.org/gems/tangram
@@ -56,9 +59,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
56
59
  version: '0'
57
60
  required_rubygems_version: !ruby/object:Gem::Requirement
58
61
  requirements:
59
- - - ">"
62
+ - - ">="
60
63
  - !ruby/object:Gem::Version
61
- version: 1.3.1
64
+ version: '0'
62
65
  requirements: []
63
66
  rubygems_version: 3.0.6
64
67
  signing_key:
@@ -1,25 +0,0 @@
1
- require 'tangram'
2
-
3
- model = Tangram::Model.from_file('./heart-disease.tangram')
4
-
5
- puts model.task
6
-
7
- input = {
8
- age: 63,
9
- gender: 'male',
10
- chest_pain: 'typical angina',
11
- resting_blood_pressure: 145,
12
- cholesterol: 233,
13
- fasting_blood_sugar_greater_than_120: 'true',
14
- resting_ecg_result: 'probable or definite left ventricular hypertrophy',
15
- exercise_max_heart_rate: 150,
16
- exercise_induced_angina: 'no',
17
- exercise_st_depression: 2.3,
18
- exercise_st_slope: 'downsloping',
19
- fluoroscopy_vessels_colored: 0,
20
- thallium_stress_test: 'fixed defect',
21
- }
22
-
23
- output = model.predict(input)
24
-
25
- puts('Prediction:', output['className'])