laya 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69d7ddd3d48590f822730d724339adf76897e8eefe51e3fb1bb6aff35fa9d5de
4
- data.tar.gz: 62fa0d3a2491c0e65d13da93712498e96249561e01859488eb8a50f5e5721fe7
3
+ metadata.gz: a6544342f63292f0739ba01c5f18aa7936869cb4871597e30cae9b1878c83dcc
4
+ data.tar.gz: 48f0ff79d462b9e0dcd331ab37cd2c72461a2c6660c3caae7bd44c437f08577e
5
5
  SHA512:
6
- metadata.gz: a83ae9a6a5f0040399b4e5ec638cc3c87e4101cf3b058ed6fb00d064cd0fc68d8f6262c58ad85f36420b1879f2be214f66205e59560246ca97f9c6759b968726
7
- data.tar.gz: a03f5b5c4563c2be24f13907acfdfdc131d2d74b7bee886b7919475593f20c6e32e7b76642fa0eab3141c20aada95a3de1b0fea57f14d6edaf3fec446fa17ea6
6
+ metadata.gz: de1897de3155feb72578637fdf567a2a5520a17e02de8b05c7b5de2e38456520ba3747814be7f81230a0c8e9b41b25051232d25a76bf5627efdc7483115ea947
7
+ data.tar.gz: 2113d85b8f13e877430fbccd4957204a8f00ac5d84690d5fc0956d6b53601819ca323d14edb8b19d6c8c9fbb79951b48b0555bf042fd5fbf07c810d404fa0c67
data/CHANGELOG.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.0 (unreleased)
3
+ ## 0.2.0
4
+
5
+ - `Laya::Client#predict` is now the primary name for running a question; `#system_one` remains as an alias
6
+
7
+ ## 0.1.0
4
8
 
5
9
  - `Laya.configure`, `Laya.new` and `Laya::Client#system_one` for `choice`, `score` and `noul` questions
6
10
  - Lazy, thread-safe model loading, with `load!` for preloading before fork
data/README.md CHANGED
@@ -1,4 +1,9 @@
1
- # laya
1
+ # Laya
2
+
3
+ [![CI](https://github.com/EduardoGHdez/laya/actions/workflows/ci.yml/badge.svg)](https://github.com/EduardoGHdez/laya/actions/workflows/ci.yml)
4
+ [![Gem Version](https://img.shields.io/gem/v/laya)](https://rubygems.org/gems/laya)
5
+ [![Ruby](https://img.shields.io/badge/ruby-%3E%3D%203.3-CC342D?logo=ruby)](https://www.ruby-lang.org)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt)
2
7
 
3
8
  Run [Laya](https://laya.convaiinnovations.com/), Convai Innovations' open-source "System-1" decision model, from Ruby. It runs locally on the CPU through ONNX Runtime.
4
9
 
@@ -7,18 +12,17 @@ You give Laya a **state** (a ticket, an email, any JSON) and some **typed questi
7
12
  ```ruby
8
13
  laya = Laya.new
9
14
 
10
- result = laya.system_one(
11
- {
12
- subject: "Refund not received",
13
- body: "I cancelled my subscription two weeks ago and I still have not received my refund. " \
14
- "This is the third time I am writing. If this is not resolved I will dispute the charge with my bank."
15
- },
16
- {
17
- department: {type: :choice, instructions: "Which team should handle this ticket?",
18
- criteria: {billing: "payments, refunds, invoices", support: "product help and bugs", sales: "new purchases"}},
19
- churn_risk: {type: :noul, instructions: "Is the customer likely to cancel or dispute?"}
20
- }
21
- )
15
+ ticket = {
16
+ subject: "Refund not received",
17
+ body: "I cancelled my subscription two weeks ago and I still have not received my refund. " \
18
+ "This is the third time I am writing. If this is not resolved I will dispute the charge with my bank."
19
+ }
20
+
21
+ result = laya.predict(ticket, {
22
+ department: {type: :choice, instructions: "Which team should handle this ticket?",
23
+ criteria: {billing: "payments, refunds, invoices", support: "product help and bugs", sales: "new purchases"}},
24
+ churn_risk: {type: :noul, instructions: "Is the customer likely to cancel or dispute?"}
25
+ })
22
26
 
23
27
  result[:department].choice # => "billing"
24
28
  result[:churn_risk].noul # => 0.0988
@@ -37,14 +41,14 @@ The model itself is about 1.7 GB, published at [receptron/laya-onnx](https://hug
37
41
 
38
42
  ## Asking questions
39
43
 
40
- `system_one(state, questions)` answers every question about one state in a single forward pass.
44
+ `predict(state, questions)` answers every question about one state in a single forward pass. `system_one` is an alias.
41
45
 
42
46
  - **`state`** is a String, or anything JSON-serializable (Hash, Array, numbers). Long states are truncated to the model's 512-token window.
43
47
  - **`questions`** is a Hash of `name => question`. Names and `type` can be Symbols or Strings, and the answers come back under the same keys.
44
48
 
45
49
  ### The three question types
46
50
 
47
- The `choice` and `score` examples below use the ticket state from the top of this README.
51
+ The `choice` and `score` examples below use `laya` and `ticket` from the top of this README.
48
52
 
49
53
  | Type | Use it for | `criteria` | Answer |
50
54
  | --- | --- | --- | --- |
@@ -55,42 +59,47 @@ The `choice` and `score` examples below use the ticket state from the top of thi
55
59
  **choice** picks the most likely label and gives the probability of each one:
56
60
 
57
61
  ```ruby
58
- department: {
59
- type: :choice,
60
- instructions: "Which team should handle this ticket?",
61
- criteria: {billing: "payments, refunds, invoices", support: "product help and bugs", sales: "new purchases"}
62
- }
63
- # result[:department].choice # => "billing"
64
- # result[:department].probabilities # => {"billing" => 0.9415, "support" => 0.031, "sales" => 0.0275}
65
- # result[:department].confidence # => 0.7603 (1 = certain, 0 = evenly spread)
62
+ result = laya.predict(ticket, {
63
+ department: {
64
+ type: :choice,
65
+ instructions: "Which team should handle this ticket?",
66
+ criteria: {billing: "payments, refunds, invoices", support: "product help and bugs", sales: "new purchases"}
67
+ }
68
+ })
69
+
70
+ result[:department].choice # => "billing"
71
+ result[:department].probabilities # => {"billing" => 0.9415, "support" => 0.031, "sales" => 0.0275}
72
+ result[:department].confidence # => 0.7603 (1 = certain, 0 = evenly spread)
66
73
  ```
67
74
 
68
75
  **score** returns the expected level, from 0 up to the number of levels minus 1, plus the distribution:
69
76
 
70
77
  ```ruby
71
- urgency: {
72
- type: :score,
73
- instructions: "How urgent is this ticket?",
74
- criteria: ["not urgent", "somewhat urgent", "urgent", "critical"]
75
- }
76
- # result[:urgency].score # => 1.3886 (between "somewhat urgent" and "urgent")
77
- # result[:urgency].probabilities # => {"0" => 0.1752, "1" => 0.2947, "2" => 0.4962, "3" => 0.0338}
78
- # result[:urgency].legend # => {"0" => "not urgent", "1" => "somewhat urgent", ...}
78
+ result = laya.predict(ticket, {
79
+ urgency: {
80
+ type: :score,
81
+ instructions: "How urgent is this ticket?",
82
+ criteria: ["not urgent", "somewhat urgent", "urgent", "critical"]
83
+ }
84
+ })
85
+
86
+ result[:urgency].score # => 1.3886 (between "somewhat urgent" and "urgent")
87
+ result[:urgency].probabilities # => {"0" => 0.1752, "1" => 0.2947, "2" => 0.4962, "3" => 0.0338}
88
+ result[:urgency].legend # => {"0" => "not urgent", "1" => "somewhat urgent", ...}
79
89
  ```
80
90
 
81
91
  **noul** returns P(true). The criteria are optional and let you say what true and false mean:
82
92
 
83
93
  ```ruby
84
- laya.system_one(
85
- "Hi, my order #4521 arrived damaged, can I get a replacement?",
86
- {
87
- spam: {
88
- type: :noul,
89
- instructions: "Is this message spam?",
90
- criteria: {true => "unsolicited advertising", false => "a genuine request"}
91
- }
94
+ result = laya.predict("Hi, my order #4521 arrived damaged, can I get a replacement?", {
95
+ spam: {
96
+ type: :noul,
97
+ instructions: "Is this message spam?",
98
+ criteria: {true => "unsolicited advertising", false => "a genuine request"}
92
99
  }
93
- )[:spam].noul # => 0.1134
100
+ })
101
+
102
+ result[:spam].noul # => 0.1134
94
103
  ```
95
104
 
96
105
  Every answer also has `type` and `act_probability`. `result.usage.input_tokens` reports how many tokens were read, and `result.to_h` returns a plain Hash.
@@ -130,7 +139,7 @@ end
130
139
 
131
140
  ### Loading and threads
132
141
 
133
- `Laya.new` is cheap: the model loads on the first `system_one` call. To load it up front, call `load!`:
142
+ `Laya.new` is cheap: the model loads on the first `predict` call. To load it up front, call `load!`:
134
143
 
135
144
  ```ruby
136
145
  LAYA = Laya.new.load!
data/lib/laya/client.rb CHANGED
@@ -21,7 +21,7 @@ module Laya
21
21
  nil
22
22
  end
23
23
 
24
- def system_one(state, questions)
24
+ def predict(state, questions)
25
25
  normalized_questions = Questions.normalize_all(questions)
26
26
  model = session
27
27
  encoded = {}
@@ -49,6 +49,7 @@ module Laya
49
49
  usage: Usage.new(input_tokens: rows.sum { |built, _| built.ids.size }, output_tokens: 0)
50
50
  )
51
51
  end
52
+ alias_method :system_one, :predict
52
53
 
53
54
  private
54
55
 
data/lib/laya/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Laya
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: laya
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eduardo Hernandez