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 +4 -4
- data/README.md +52 -1
- data/examples/monitor/heart-disease.tangram +0 -0
- data/examples/monitor/main.rb +52 -0
- data/examples/predict/heart-disease.tangram +0 -0
- data/examples/predict/main.rb +30 -0
- data/lib/tangram/libtangram-0.1.0-linux-x86_64.so +0 -0
- data/lib/tangram/libtangram-0.1.0-macos-x86_64.dylib +0 -0
- data/lib/tangram/libtangram.rb +4 -4
- data/lib/tangram/model.rb +92 -8
- data/lib/tangram/{tangram-0.1.0-alpha.4-windows-x86_64.dll → tangram-0.1.0-windows-x86_64.dll} +0 -0
- data/tangram.gemspec +1 -2
- metadata +11 -8
- data/examples/heart-disease/main.rb +0 -25
- data/lib/tangram/libtangram-0.1.0-alpha.4-linux-x86_64.so +0 -0
- data/lib/tangram/libtangram-0.1.0-alpha.4-macos-x86_64.dylib +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e622eeb9d9cd659b75acbf6dc167a0685a5111ab35a434c888c497de99faf742
|
4
|
+
data.tar.gz: 91c21be6670a9e3d3072648dba57b570a4cc313958af8a5a16ee7588f461c9b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5079553215b584e04826f4e522e5b47587711e7493c389f587ec2202acc33a72a9f769d1155e11f746bbb69320a4d2a3bee587701b33877a558ddf467d7d967c
|
7
|
+
data.tar.gz: 0d86be9c1a11e988cbcd6549ae9eb55c0cde9126ab85f1f99f23f796100c158ee32401fe92e0a63b28bacee114cf3a15f2cf0af6b265bf3dbd03717ed44bd86d
|
data/README.md
CHANGED
@@ -1 +1,52 @@
|
|
1
|
-
#
|
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).
|
Binary file
|
@@ -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
|
+
)
|
Binary file
|
@@ -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)
|
Binary file
|
Binary file
|
data/lib/tangram/libtangram.rb
CHANGED
@@ -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-
|
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-
|
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-
|
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
|
-
|
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
|
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/lib/tangram/{tangram-0.1.0-alpha.4-windows-x86_64.dll → tangram-0.1.0-windows-x86_64.dll}
RENAMED
Binary file
|
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.
|
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.
|
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:
|
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
|
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-
|
38
|
-
- lib/tangram/libtangram-0.1.0-
|
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-
|
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:
|
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'])
|
Binary file
|
Binary file
|