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 +4 -4
- data/CHANGELOG.md +5 -1
- data/README.md +50 -41
- data/lib/laya/client.rb +2 -1
- data/lib/laya/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a6544342f63292f0739ba01c5f18aa7936869cb4871597e30cae9b1878c83dcc
|
|
4
|
+
data.tar.gz: 48f0ff79d462b9e0dcd331ab37cd2c72461a2c6660c3caae7bd44c437f08577e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: de1897de3155feb72578637fdf567a2a5520a17e02de8b05c7b5de2e38456520ba3747814be7f81230a0c8e9b41b25051232d25a76bf5627efdc7483115ea947
|
|
7
|
+
data.tar.gz: 2113d85b8f13e877430fbccd4957204a8f00ac5d84690d5fc0956d6b53601819ca323d14edb8b19d6c8c9fbb79951b48b0555bf042fd5fbf07c810d404fa0c67
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
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
|
-
#
|
|
1
|
+
# Laya
|
|
2
|
+
|
|
3
|
+
[](https://github.com/EduardoGHdez/laya/actions/workflows/ci.yml)
|
|
4
|
+
[](https://rubygems.org/gems/laya)
|
|
5
|
+
[](https://www.ruby-lang.org)
|
|
6
|
+
[](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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
`
|
|
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
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
)
|
|
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 `
|
|
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
|
|
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