rager 0.1.0 → 0.2.1

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +0 -0
  3. data/README.md +5 -2
  4. data/lib/rager/chat/message.rb +0 -0
  5. data/lib/rager/chat/message_content.rb +0 -0
  6. data/lib/rager/chat/message_content_image_type.rb +0 -0
  7. data/lib/rager/chat/message_content_type.rb +0 -0
  8. data/lib/rager/chat/message_delta.rb +0 -0
  9. data/lib/rager/chat/message_role.rb +0 -0
  10. data/lib/rager/chat/options.rb +0 -0
  11. data/lib/rager/chat/providers/abstract.rb +0 -0
  12. data/lib/rager/chat/providers/openai.rb +1 -1
  13. data/lib/rager/chat/schema.rb +0 -0
  14. data/lib/rager/chat.rb +0 -0
  15. data/lib/rager/config.rb +0 -0
  16. data/lib/rager/context.rb +71 -5
  17. data/lib/rager/embed/options.rb +30 -0
  18. data/lib/rager/embed/providers/abstract.rb +25 -0
  19. data/lib/rager/embed/providers/openai.rb +61 -0
  20. data/lib/rager/embed.rb +35 -0
  21. data/lib/rager/error.rb +0 -0
  22. data/lib/rager/errors/http_error.rb +0 -0
  23. data/lib/rager/errors/missing_credentials_error.rb +0 -0
  24. data/lib/rager/errors/options_error.rb +0 -0
  25. data/lib/rager/errors/parse_error.rb +0 -0
  26. data/lib/rager/errors/template_error.rb +18 -0
  27. data/lib/rager/errors/unknown_provider_error.rb +0 -0
  28. data/lib/rager/http/adapters/abstract.rb +0 -0
  29. data/lib/rager/http/adapters/async_http.rb +3 -1
  30. data/lib/rager/http/adapters/mock.rb +0 -0
  31. data/lib/rager/http/request.rb +0 -0
  32. data/lib/rager/http/response.rb +0 -0
  33. data/lib/rager/http/verb.rb +0 -0
  34. data/lib/rager/image_gen/options.rb +0 -0
  35. data/lib/rager/image_gen/providers/abstract.rb +0 -0
  36. data/lib/rager/image_gen/providers/replicate.rb +0 -0
  37. data/lib/rager/image_gen.rb +0 -0
  38. data/lib/rager/logger.rb +0 -0
  39. data/lib/rager/mesh_gen/options.rb +0 -0
  40. data/lib/rager/mesh_gen/providers/abstract.rb +0 -0
  41. data/lib/rager/mesh_gen/providers/replicate.rb +0 -0
  42. data/lib/rager/mesh_gen.rb +0 -0
  43. data/lib/rager/operation.rb +4 -0
  44. data/lib/rager/options.rb +0 -0
  45. data/lib/rager/rerank/options.rb +30 -0
  46. data/lib/rager/rerank/providers/abstract.rb +25 -0
  47. data/lib/rager/rerank/providers/cohere.rb +73 -0
  48. data/lib/rager/rerank/query.rb +13 -0
  49. data/lib/rager/rerank/result.rb +13 -0
  50. data/lib/rager/rerank.rb +35 -0
  51. data/lib/rager/result.rb +38 -6
  52. data/lib/rager/search/options.rb +28 -0
  53. data/lib/rager/search/providers/abstract.rb +25 -0
  54. data/lib/rager/search/providers/brave.rb +76 -0
  55. data/lib/rager/search/result.rb +14 -0
  56. data/lib/rager/search.rb +35 -0
  57. data/lib/rager/template/input.rb +11 -0
  58. data/lib/rager/template/options.rb +22 -0
  59. data/lib/rager/template/providers/abstract.rb +26 -0
  60. data/lib/rager/template/providers/erb.rb +26 -0
  61. data/lib/rager/template.rb +35 -0
  62. data/lib/rager/types.rb +29 -6
  63. data/lib/rager/version.rb +1 -1
  64. data/lib/rager.rb +0 -0
  65. metadata +36 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b4311f3da8c6cf4e479c8c951322e329b4f4d697a8f78c6b2945b89793a2903
4
- data.tar.gz: b92e1be42bcf7a769da8d1164f0dcd0d3108249bf3e1266cf1f2b0612bdab69f
3
+ metadata.gz: 32cd931dd6c3c714456232f7aeb15743580a605330051a31c4167a0435e8d766
4
+ data.tar.gz: bd28897b484c9b6d0972b229b6fe834eb532b1027baf855b33ac9940df303c8a
5
5
  SHA512:
6
- metadata.gz: 7bb128546a71dc3e61e28d7c7ffbbfaa7dfdbf1f3b5236de89eb7c9069cb94d45ca5b3336650ee4e7d29a9cfbb8b4a88ead87134ff0b781aba08c3c90ce5b00d
7
- data.tar.gz: bcdb5dbd47c1fc6f7014e321349aa95102c6cd1492872755afe5ca32101d7cd9aa68b24c4eb98021c2cd19edc44479121c01f5ce118f4b539ffc39a5979019cb
6
+ metadata.gz: 9b98958d909a001eb2f21a65e1186a473fa5c11e1e86255e0d9c9cfdd535b3ce6131c90c1fa9b5665fe4831f168860d49e399b9b25d0bcd179b2a022e9db8d7a
7
+ data.tar.gz: 70d77abac363b663d6b82636b93af19bddf02f37570599e6df71e6a2f0f30fbb309d87b2f8431bdf4106bf9e3559448579b66ac8cd2cb34eca2b3ccca0f98bbe
data/LICENSE.md CHANGED
File without changes
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # rager_rb
2
2
 
3
- [![test](https://github.com/mvkvc/rager_rb/actions/workflows/test.yaml/badge.svg)](https://github.com/mvkvc/rager_rb/actions/workflows/test.yaml)
3
+ [![gem](https://badge.fury.io/rb/rager.svg?icon=si%3Arubygems)](https://badge.fury.io/rb/rager)
4
+ [![publish](https://github.com/mvkvc/rager_rb/actions/workflows/publish.yml/badge.svg?branch=main)](https://github.com/mvkvc/rager_rb/actions/workflows/publish.yml)
5
+ [![test](https://github.com/mvkvc/rager_rb/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/mvkvc/rager_rb/actions/workflows/test.yml)
6
+ [![lint](https://github.com/mvkvc/rager_rb/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/mvkvc/rager_rb/actions/workflows/lint.yml)
4
7
 
5
8
  Build continuously improving AI applications.
6
9
 
@@ -15,7 +18,7 @@ bundle add rager
15
18
  Otherwise you can add it to your Gemfile directly:
16
19
 
17
20
  ```Ruby
18
- gem "rager", "~> 0.1.0"
21
+ gem "rager", "~> 0.2.0"
19
22
  ```
20
23
 
21
24
  ## License
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -23,7 +23,7 @@ module Rager
23
23
  raise Rager::Errors::MissingCredentialsError.new("OpenAI", "OPENAI_API_KEY") if api_key.nil?
24
24
 
25
25
  url = options.url || ENV["OPENAI_URL"] || "https://api.openai.com/v1/chat/completions"
26
- model = options.model || "gpt-4o"
26
+ model = options.model || "gpt-4.1"
27
27
 
28
28
  openai_messages = build_openai_messages(messages, options.history, options.system_prompt)
29
29
 
File without changes
data/lib/rager/chat.rb CHANGED
File without changes
data/lib/rager/config.rb CHANGED
File without changes
data/lib/rager/context.rb CHANGED
@@ -44,6 +44,25 @@ module Rager
44
44
  ) { |options| Chat.chat(messages, options) }
45
45
  end
46
46
 
47
+ sig do
48
+ params(
49
+ text: T.any(String, T::Array[String]),
50
+ kwargs: T.untyped
51
+ ).returns(Rager::Result)
52
+ end
53
+ def embed(text, **kwargs)
54
+ if text.is_a?(String)
55
+ text = [text]
56
+ end
57
+
58
+ execute(
59
+ Rager::Operation::Embed,
60
+ Rager::Embed::Options,
61
+ kwargs,
62
+ text
63
+ ) { |options| Embed.embed(text, options) }
64
+ end
65
+
47
66
  sig do
48
67
  params(
49
68
  prompt: String,
@@ -74,6 +93,51 @@ module Rager
74
93
  ) { |options| MeshGen.mesh_gen(prompt, options) }
75
94
  end
76
95
 
96
+ sig do
97
+ params(
98
+ query: Rager::Rerank::Query,
99
+ kwargs: T.untyped
100
+ ).returns(Rager::Result)
101
+ end
102
+ def rerank(query, **kwargs)
103
+ execute(
104
+ Rager::Operation::Rerank,
105
+ Rager::Rerank::Options,
106
+ kwargs,
107
+ query
108
+ ) { |options| Rager::Rerank.rerank(query, options) }
109
+ end
110
+
111
+ sig do
112
+ params(
113
+ query: String,
114
+ kwargs: T.untyped
115
+ ).returns(Rager::Result)
116
+ end
117
+ def search(query, **kwargs)
118
+ execute(
119
+ Rager::Operation::Search,
120
+ Rager::Search::Options,
121
+ kwargs,
122
+ query
123
+ ) { |options| Search.search(query, options) }
124
+ end
125
+
126
+ sig do
127
+ params(
128
+ input: Rager::Template::Input,
129
+ kwargs: T.untyped
130
+ ).returns(Rager::Result)
131
+ end
132
+ def template(input, **kwargs)
133
+ execute(
134
+ Rager::Operation::Template,
135
+ Rager::Template::Options,
136
+ kwargs,
137
+ input
138
+ ) { |options| Template.template(input, options) }
139
+ end
140
+
77
141
  private
78
142
 
79
143
  sig do
@@ -81,11 +145,13 @@ module Rager
81
145
  operation: Rager::Operation,
82
146
  options_struct: T::Class[Rager::Options],
83
147
  kwargs: T.untyped,
84
- input: T.any(String, T::Array[Rager::Chat::Message]),
148
+ input: Rager::Types::Input,
85
149
  block: T.proc.params(options: T.untyped).returns(T.untyped)
86
150
  ).returns(Rager::Result)
87
151
  end
88
152
  def execute(operation, options_struct, kwargs, input, &block)
153
+ input_ids = kwargs.delete(:input_ids)
154
+
89
155
  options = options_struct.new(**kwargs)
90
156
  options.validate
91
157
 
@@ -94,6 +160,7 @@ module Rager
94
160
  output = yield(options)
95
161
 
96
162
  Result.new(
163
+ id: @id,
97
164
  context_id: @id,
98
165
  hash: @hash,
99
166
  operation: operation,
@@ -101,12 +168,11 @@ module Rager
101
168
  options: options,
102
169
  start_time: start_time.to_i,
103
170
  end_time: Time.now.to_i,
104
- output: output
105
- ).tap { |r| r.log }
171
+ output: output,
172
+ input_ids: input_ids
173
+ ).tap(&:log)
106
174
  end
107
175
 
108
- private
109
-
110
176
  sig { returns(T.nilable(String)) }
111
177
  def lookup_git_hash
112
178
  result = `git rev-parse HEAD`
@@ -0,0 +1,30 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Embed
8
+ class Options < T::Struct
9
+ extend T::Sig
10
+ include Rager::Options
11
+
12
+ const :provider, String, default: "openai"
13
+ const :url, T.nilable(String)
14
+ const :model, T.nilable(String)
15
+ const :api_key, T.nilable(String)
16
+ const :seed, T.nilable(Integer)
17
+
18
+ sig { override.returns(T::Hash[String, T.untyped]) }
19
+ def serialize_safe
20
+ result = serialize
21
+ result["api_key"] = "[REDACTED]" if result.key?("api_key")
22
+ result
23
+ end
24
+
25
+ sig { override.void }
26
+ def validate
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Embed
8
+ module Providers
9
+ class Abstract
10
+ extend T::Sig
11
+ extend T::Helpers
12
+ abstract!
13
+
14
+ sig do
15
+ abstract.params(
16
+ text: T::Array[String],
17
+ options: Rager::Embed::Options
18
+ ).returns(Rager::Types::EmbedOutput)
19
+ end
20
+ def embed(text, options)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,61 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "json"
5
+ require "sorbet-runtime"
6
+
7
+ module Rager
8
+ module Embed
9
+ module Providers
10
+ class Openai < Rager::Embed::Providers::Abstract
11
+ extend T::Sig
12
+
13
+ sig do
14
+ override.params(
15
+ text: T::Array[String],
16
+ options: Rager::Embed::Options
17
+ ).returns(Rager::Types::EmbedOutput)
18
+ end
19
+ def embed(text, options)
20
+ api_key = options.api_key || ENV["OPENAI_API_KEY"]
21
+ raise Rager::Errors::MissingCredentialsError.new("OpenAI", "OPENAI_API_KEY") if api_key.nil?
22
+
23
+ url = options.url || ENV["OPENAI_URL"] || "https://api.openai.com/v1/embeddings"
24
+ model = options.model || "text-embedding-3-large"
25
+
26
+ headers = {
27
+ "Content-Type" => "application/json"
28
+ }
29
+ headers["Authorization"] = "Bearer #{api_key}" if api_key
30
+
31
+ body = {
32
+ model: model,
33
+ input: text
34
+ }
35
+
36
+ request = Rager::Http::Request.new(
37
+ verb: Rager::Http::Verb::Post,
38
+ url: url,
39
+ headers: headers,
40
+ body: body.to_json
41
+ )
42
+
43
+ http_adapter = Rager.config.http_adapter
44
+ response = http_adapter.make_request(request)
45
+ response_body = T.cast(T.must(response.body), String)
46
+
47
+ if response.status != 200
48
+ raise Rager::Errors::HttpError.new(
49
+ http_adapter,
50
+ response.status,
51
+ response_body
52
+ )
53
+ end
54
+
55
+ parsed_response = JSON.parse(response_body)
56
+ parsed_response["data"].map { |item| item["embedding"] }
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,35 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Embed
8
+ extend T::Sig
9
+
10
+ sig do
11
+ params(
12
+ text: T::Array[String],
13
+ options: Rager::Embed::Options
14
+ ).returns(Rager::Types::EmbedOutput)
15
+ end
16
+ def self.embed(text, options = Rager::Embed::Options.new)
17
+ provider = get_provider(options.provider)
18
+ provider.embed(text, options)
19
+ end
20
+
21
+ sig do
22
+ params(
23
+ key: String
24
+ ).returns(Rager::Embed::Providers::Abstract)
25
+ end
26
+ def self.get_provider(key)
27
+ case key.downcase
28
+ when "openai"
29
+ Rager::Embed::Providers::Openai.new
30
+ else
31
+ raise Rager::Errors::UnknownProviderError.new(Rager::Operation::Embed, key)
32
+ end
33
+ end
34
+ end
35
+ end
data/lib/rager/error.rb CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,18 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Errors
8
+ class TemplateError < Rager::Error
9
+ extend T::Sig
10
+
11
+ sig { params(input: Rager::Template::Input, message: String).void }
12
+ def initialize(input, message)
13
+ message = "Template Error: #{message} in #{input.template}"
14
+ super(message)
15
+ end
16
+ end
17
+ end
18
+ end
File without changes
File without changes
@@ -35,7 +35,9 @@ module Rager
35
35
  response.headers["content-type"]&.downcase&.include?("text/event-stream")
36
36
  body_enum(response)
37
37
  else
38
- response.body.read
38
+ body_parts = []
39
+ response.body.each { |chunk| body_parts << chunk }
40
+ body_parts.join.force_encoding("UTF-8")
39
41
  end
40
42
 
41
43
  Response.new(
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
data/lib/rager/logger.rb CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -7,8 +7,12 @@ module Rager
7
7
  class Operation < T::Enum
8
8
  enums do
9
9
  Chat = new("chat")
10
+ Embed = new("embed")
10
11
  ImageGen = new("image_gen")
11
12
  MeshGen = new("mesh_gen")
13
+ Rerank = new("rerank")
14
+ Search = new("search")
15
+ Template = new("template")
12
16
  end
13
17
  end
14
18
  end
data/lib/rager/options.rb CHANGED
File without changes
@@ -0,0 +1,30 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Rerank
8
+ class Options < T::Struct
9
+ extend T::Sig
10
+ include Rager::Options
11
+
12
+ const :provider, String, default: "cohere"
13
+ const :url, T.nilable(String)
14
+ const :model, T.nilable(String)
15
+ const :n, T.nilable(Integer)
16
+ const :api_key, T.nilable(String)
17
+
18
+ sig { override.returns(T::Hash[String, T.untyped]) }
19
+ def serialize_safe
20
+ result = serialize
21
+ result["api_key"] = "[REDACTED]" if result.key?("api_key")
22
+ result
23
+ end
24
+
25
+ sig { override.void }
26
+ def validate
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Rerank
8
+ module Providers
9
+ class Abstract
10
+ extend T::Sig
11
+ extend T::Helpers
12
+ abstract!
13
+
14
+ sig do
15
+ abstract.params(
16
+ query: Rager::Rerank::Query,
17
+ options: Rager::Rerank::Options
18
+ ).returns(Rager::Types::RerankOutput)
19
+ end
20
+ def rerank(query, options)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,73 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "json"
5
+ require "sorbet-runtime"
6
+
7
+ module Rager
8
+ module Rerank
9
+ module Providers
10
+ class Cohere < Rager::Rerank::Providers::Abstract
11
+ extend T::Sig
12
+
13
+ sig do
14
+ override.params(
15
+ query: Rager::Rerank::Query,
16
+ options: Rager::Rerank::Options
17
+ ).returns(Rager::Types::RerankOutput)
18
+ end
19
+ def rerank(query, options)
20
+ api_key = options.api_key || ENV["COHERE_API_KEY"]
21
+ raise Rager::Errors::MissingCredentialsError.new("Cohere", "COHERE_API_KEY") if api_key.nil?
22
+
23
+ url = options.url || ENV["COHERE_URL"] || "https://api.cohere.com/v2/rerank"
24
+ model = options.model || "rerank-v3.5"
25
+
26
+ headers = {
27
+ "Content-Type" => "application/json"
28
+ }
29
+ headers["Authorization"] = "Bearer #{api_key}" if api_key
30
+
31
+ body = {
32
+ model: model,
33
+ query: query.query,
34
+ documents: query.documents
35
+ }
36
+ body[:top_n] = options.n if options.n
37
+
38
+ request = Rager::Http::Request.new(
39
+ verb: Rager::Http::Verb::Post,
40
+ url: url,
41
+ headers: headers,
42
+ body: body.to_json
43
+ )
44
+
45
+ http_adapter = Rager.config.http_adapter
46
+ response = http_adapter.make_request(request)
47
+ response_body = T.cast(T.must(response.body), String)
48
+
49
+ if response.status != 200
50
+ raise Rager::Errors::HttpError.new(
51
+ http_adapter,
52
+ response.status,
53
+ response_body
54
+ )
55
+ end
56
+
57
+ parsed_response = JSON.parse(response_body)
58
+
59
+ results = parsed_response["results"] || []
60
+ results.map do |result|
61
+ index = result["index"]
62
+ score = result["relevance_score"]
63
+
64
+ Rager::Rerank::Result.new(
65
+ score: score,
66
+ index: index
67
+ )
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,13 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Rerank
8
+ class Query < T::Struct
9
+ const :query, String
10
+ const :documents, T::Array[String]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Rerank
8
+ class Result < T::Struct
9
+ const :score, Float
10
+ const :index, Integer
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Rerank
8
+ extend T::Sig
9
+
10
+ sig do
11
+ params(
12
+ query: Rager::Rerank::Query,
13
+ options: Rager::Rerank::Options
14
+ ).returns(Rager::Types::RerankOutput)
15
+ end
16
+ def self.rerank(query, options = Rager::Rerank::Options.new)
17
+ provider = get_provider(options.provider)
18
+ provider.rerank(query, options)
19
+ end
20
+
21
+ sig do
22
+ params(
23
+ key: String
24
+ ).returns(Rager::Rerank::Providers::Abstract)
25
+ end
26
+ def self.get_provider(key)
27
+ case key.downcase
28
+ when "cohere"
29
+ Rager::Rerank::Providers::Cohere.new
30
+ else
31
+ raise Rager::Errors::UnknownProviderError.new(Rager::Operation::Rerank, key)
32
+ end
33
+ end
34
+ end
35
+ end
data/lib/rager/result.rb CHANGED
@@ -9,6 +9,9 @@ module Rager
9
9
  class Result
10
10
  extend T::Sig
11
11
 
12
+ sig { returns(String) }
13
+ attr_reader :id
14
+
12
15
  sig { returns(Rager::Operation) }
13
16
  attr_reader :operation
14
17
 
@@ -33,8 +36,12 @@ module Rager
33
36
  sig { returns(T.nilable(String)) }
34
37
  attr_reader :hash
35
38
 
39
+ sig { returns(T.nilable(T::Array[String])) }
40
+ attr_reader :input_ids
41
+
36
42
  sig do
37
43
  params(
44
+ id: String,
38
45
  operation: Rager::Operation,
39
46
  options: Rager::Options,
40
47
  input: Rager::Types::Input,
@@ -42,10 +49,12 @@ module Rager
42
49
  start_time: Integer,
43
50
  end_time: Integer,
44
51
  context_id: T.nilable(String),
45
- hash: T.nilable(String)
52
+ hash: T.nilable(String),
53
+ input_ids: T.nilable(T::Array[String])
46
54
  ).void
47
55
  end
48
56
  def initialize(
57
+ id:,
49
58
  operation:,
50
59
  options:,
51
60
  input:,
@@ -53,8 +62,10 @@ module Rager
53
62
  start_time:,
54
63
  end_time:,
55
64
  context_id: nil,
56
- hash: nil
65
+ hash: nil,
66
+ input_ids: nil
57
67
  )
68
+ @id = id
58
69
  @operation = operation
59
70
  @options = options
60
71
  @input = input
@@ -67,6 +78,7 @@ module Rager
67
78
  @result_id = T.let(SecureRandom.uuid, T.nilable(String))
68
79
  @context_id = T.let(context_id, T.nilable(String))
69
80
  @hash = T.let(hash, T.nilable(String))
81
+ @input_ids = T.let(input_ids, T.nilable(T::Array[String]))
70
82
  end
71
83
 
72
84
  sig { returns(T::Boolean) }
@@ -117,13 +129,31 @@ module Rager
117
129
  .map { |_, content| content }
118
130
  end
119
131
 
120
- sig { returns(T.any(String, T::Array[T::Hash[String, T.untyped]])) }
132
+ sig do
133
+ returns(
134
+ T.any(
135
+ String,
136
+ T::Hash[String, T.untyped],
137
+ T::Array[T.untyped]
138
+ )
139
+ )
140
+ end
121
141
  def serialize_input
122
142
  case @input
123
143
  when String
124
144
  @input
145
+ when Rager::Rerank::Query
146
+ @input.serialize
147
+ when Rager::Template::Input
148
+ @input.serialize
125
149
  when Array
126
- @input.map(&:serialize)
150
+ @input.map do |item|
151
+ if !item.is_a?(String)
152
+ item.serialize
153
+ else
154
+ item
155
+ end
156
+ end
127
157
  end
128
158
  end
129
159
 
@@ -141,6 +171,7 @@ module Rager
141
171
  sig { returns(T::Hash[String, T.untyped]) }
142
172
  def to_h
143
173
  {
174
+ id: @id,
144
175
  operation: @operation.serialize,
145
176
  options: @options.serialize_safe,
146
177
  input: serialize_input,
@@ -155,7 +186,8 @@ module Rager
155
186
  end_time: @end_time,
156
187
  result_id: @result_id,
157
188
  context_id: @context_id,
158
- hash: @hash
189
+ hash: @hash,
190
+ input_ids: @input_ids
159
191
  }
160
192
  end
161
193
 
@@ -167,7 +199,7 @@ module Rager
167
199
 
168
200
  case Rager.config.logger
169
201
  when Rager::Logger::Stdout
170
- puts "LOG: #{json}"
202
+ puts "\nLOG: #{json}"
171
203
  when Rager::Logger::Remote
172
204
  http_adapter = Rager.config.http_adapter
173
205
  url = Rager.config.url
@@ -0,0 +1,28 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Search
8
+ class Options < T::Struct
9
+ extend T::Sig
10
+ include Rager::Options
11
+
12
+ const :provider, String, default: "brave"
13
+ const :n, T.nilable(Integer)
14
+ const :api_key, T.nilable(String)
15
+
16
+ sig { override.returns(T::Hash[String, T.untyped]) }
17
+ def serialize_safe
18
+ result = serialize
19
+ result["api_key"] = "[REDACTED]" if result.key?("api_key")
20
+ result
21
+ end
22
+
23
+ sig { override.void }
24
+ def validate
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Search
8
+ module Providers
9
+ class Abstract
10
+ extend T::Sig
11
+ extend T::Helpers
12
+ abstract!
13
+
14
+ sig do
15
+ abstract.params(
16
+ query: String,
17
+ options: Rager::Search::Options
18
+ ).returns(Rager::Types::SearchOutput)
19
+ end
20
+ def search(query, options)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,76 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "json"
5
+ require "uri"
6
+ require "sorbet-runtime"
7
+
8
+ module Rager
9
+ module Search
10
+ module Providers
11
+ class Brave < Rager::Search::Providers::Abstract
12
+ extend T::Sig
13
+
14
+ sig do
15
+ override.params(
16
+ query: String,
17
+ options: Rager::Search::Options
18
+ ).returns(Rager::Types::SearchOutput)
19
+ end
20
+ def search(query, options)
21
+ api_key = options.api_key || ENV["BRAVE_API_KEY"]
22
+ raise Rager::Errors::MissingCredentialsError.new("Brave", "BRAVE_API_KEY") if api_key.nil?
23
+
24
+ params = {"q" => query}
25
+ params["count"] = options.n.to_s if options.n
26
+
27
+ query_string = URI.encode_www_form(params)
28
+ url = "https://api.search.brave.com/res/v1/web/search?#{query_string}"
29
+
30
+ headers = {
31
+ "Accept" => "application/json",
32
+ "Accept-Encoding" => "gzip",
33
+ "x-subscription-token" => api_key
34
+ }
35
+
36
+ request = Rager::Http::Request.new(
37
+ verb: Rager::Http::Verb::Get,
38
+ url: url,
39
+ headers: headers
40
+ )
41
+
42
+ http_adapter = Rager.config.http_adapter
43
+ response = http_adapter.make_request(request)
44
+ response_body = T.cast(T.must(response.body), String)
45
+
46
+ if response.status != 200
47
+ raise Rager::Errors::HttpError.new(
48
+ http_adapter,
49
+ response.status,
50
+ response_body
51
+ )
52
+ end
53
+
54
+ parsed_response = JSON.parse(response_body)
55
+
56
+ results = []
57
+
58
+ if parsed_response["web"] && parsed_response["web"]["results"]
59
+ web_results = parsed_response["web"]["results"]
60
+ web_results.each do |result|
61
+ next unless result["title"] && result["url"] && result["description"]
62
+
63
+ results << Rager::Search::Result.new(
64
+ title: result["title"],
65
+ url: result["url"],
66
+ description: result["description"]
67
+ )
68
+ end
69
+ end
70
+
71
+ results
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,14 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Search
8
+ class Result < T::Struct
9
+ const :title, String
10
+ const :url, String
11
+ const :description, String
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,35 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Search
8
+ extend T::Sig
9
+
10
+ sig do
11
+ params(
12
+ query: String,
13
+ options: Rager::Search::Options
14
+ ).returns(Rager::Types::SearchOutput)
15
+ end
16
+ def self.search(query, options = Rager::Search::Options.new)
17
+ provider = get_provider(options.provider)
18
+ provider.search(query, options)
19
+ end
20
+
21
+ sig do
22
+ params(
23
+ key: String
24
+ ).returns(Rager::Search::Providers::Abstract)
25
+ end
26
+ def self.get_provider(key)
27
+ case key.downcase
28
+ when "brave"
29
+ Rager::Search::Providers::Brave.new
30
+ else
31
+ raise Rager::Errors::UnknownProviderError.new(Rager::Operation::Search, key)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Rager
5
+ module Template
6
+ class Input < T::Struct
7
+ const :template, String
8
+ const :variables, T::Hash[Symbol, T.untyped]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Rager
5
+ module Template
6
+ class Options < T::Struct
7
+ include Rager::Options
8
+ extend T::Sig
9
+
10
+ const :provider, String, default: "erb"
11
+
12
+ sig { override.returns(T::Hash[String, T.untyped]) }
13
+ def serialize_safe
14
+ serialize.transform_keys(&:to_s)
15
+ end
16
+
17
+ sig { override.void }
18
+ def validate
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Template
8
+ module Providers
9
+ class Abstract
10
+ extend T::Sig
11
+ extend T::Helpers
12
+
13
+ abstract!
14
+
15
+ sig do
16
+ abstract.params(
17
+ input: Rager::Template::Input,
18
+ options: Rager::Template::Options
19
+ ).returns(Rager::Types::TemplateOutput)
20
+ end
21
+ def template(input, options)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "erb"
5
+ require "ostruct"
6
+
7
+ module Rager
8
+ module Template
9
+ module Providers
10
+ class Erb < Rager::Template::Providers::Abstract
11
+ extend T::Sig
12
+
13
+ sig do
14
+ override.params(
15
+ input: Rager::Template::Input,
16
+ options: Rager::Template::Options
17
+ ).returns(Rager::Types::TemplateOutput)
18
+ end
19
+ def template(input, options)
20
+ scope = OpenStruct.new(input.variables)
21
+ ERB.new(input.template).result(scope.instance_eval { binding })
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,35 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Template
8
+ extend T::Sig
9
+
10
+ sig do
11
+ params(
12
+ input: Rager::Template::Input,
13
+ options: Rager::Template::Options
14
+ ).returns(Rager::Types::TemplateOutput)
15
+ end
16
+ def self.template(input, options = Rager::Template::Options.new)
17
+ provider = get_provider(options.provider)
18
+ provider.template(input, options)
19
+ end
20
+
21
+ sig do
22
+ params(
23
+ key: String
24
+ ).returns(Rager::Template::Providers::Abstract)
25
+ end
26
+ def self.get_provider(key)
27
+ case key.downcase
28
+ when "erb"
29
+ Rager::Template::Providers::Erb.new
30
+ else
31
+ raise Rager::Errors::UnknownProviderError.new(Rager::Operation::Template, key)
32
+ end
33
+ end
34
+ end
35
+ end
data/lib/rager/types.rb CHANGED
@@ -5,40 +5,63 @@ module Rager
5
5
  module Types
6
6
  extend T::Sig
7
7
 
8
- ChatInput = T.type_alias { T.any(String, T::Array[Rager::Chat::Message]) }
8
+ ChatInput = T.type_alias { T::Array[Rager::Chat::Message] }
9
+ EmbedInput = T.type_alias { T::Array[String] }
9
10
  ImageGenInput = T.type_alias { String }
10
11
  MeshGenInput = T.type_alias { String }
12
+ RerankInput = T.type_alias { Rager::Rerank::Query }
13
+ SearchInput = T.type_alias { String }
14
+ TemplateInput = T.type_alias { Rager::Template::Input }
11
15
  Input = T.type_alias {
12
16
  T.any(
13
17
  ChatInput,
18
+ EmbedInput,
14
19
  ImageGenInput,
15
- MeshGenInput
20
+ MeshGenInput,
21
+ RerankInput,
22
+ SearchInput,
23
+ TemplateInput
16
24
  )
17
25
  }
18
26
 
27
+ ChatNonStream = T.type_alias { T::Array[String] }
28
+
19
29
  ChatStream = T.type_alias { T::Enumerator[Rager::Chat::MessageDelta] }
20
30
  Stream = T.type_alias { ChatStream }
21
31
 
22
32
  ChatBuffer = T.type_alias { T::Array[Rager::Chat::MessageDelta] }
23
33
  Buffer = T.type_alias { ChatBuffer }
24
34
 
25
- ChatOutput = T.type_alias { T.any(T::Array[String], ChatStream) }
35
+ ChatOutput = T.type_alias { T.any(ChatNonStream, ChatStream) }
36
+ EmbedOutput = T.type_alias { T::Array[T::Array[Float]] }
26
37
  ImageGenOutput = T.type_alias { String }
27
38
  MeshGenOutput = T.type_alias { String }
39
+ RerankOutput = T.type_alias { T::Array[Rager::Rerank::Result] }
40
+ SearchOutput = T.type_alias { T::Array[Rager::Search::Result] }
41
+ TemplateOutput = T.type_alias { String }
28
42
  Output = T.type_alias {
29
43
  T.any(
30
44
  ChatOutput,
45
+ EmbedOutput,
31
46
  ImageGenOutput,
32
- MeshGenOutput
47
+ MeshGenOutput,
48
+ RerankOutput,
49
+ SearchOutput,
50
+ TemplateOutput
33
51
  )
34
52
  }
35
53
 
36
- ChatNonStreamOutput = T.type_alias { T::Array[String] }
54
+ ChatNonStreamOutput = T.type_alias { ChatNonStream }
55
+
37
56
  NonStreamOutput = T.type_alias {
38
57
  T.any(
39
58
  ChatNonStreamOutput,
59
+ EmbedOutput,
40
60
  ImageGenOutput,
41
- MeshGenOutput
61
+ MeshGenOutput,
62
+ RerankOutput,
63
+ SearchOutput,
64
+ TemplateOutput
42
65
  )
43
66
  }
44
67
  end
data/lib/rager/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Rager
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.1"
6
6
  end
data/lib/rager.rb CHANGED
File without changes
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rager
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - mvkvc
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '1.14'
26
+ - !ruby/object:Gem::Dependency
27
+ name: ostruct
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.6.2
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.6.2
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: sorbet-runtime
28
42
  requirement: !ruby/object:Gem::Requirement
@@ -73,11 +87,16 @@ files:
73
87
  - lib/rager/chat/schema.rb
74
88
  - lib/rager/config.rb
75
89
  - lib/rager/context.rb
90
+ - lib/rager/embed.rb
91
+ - lib/rager/embed/options.rb
92
+ - lib/rager/embed/providers/abstract.rb
93
+ - lib/rager/embed/providers/openai.rb
76
94
  - lib/rager/error.rb
77
95
  - lib/rager/errors/http_error.rb
78
96
  - lib/rager/errors/missing_credentials_error.rb
79
97
  - lib/rager/errors/options_error.rb
80
98
  - lib/rager/errors/parse_error.rb
99
+ - lib/rager/errors/template_error.rb
81
100
  - lib/rager/errors/unknown_provider_error.rb
82
101
  - lib/rager/http/adapters/abstract.rb
83
102
  - lib/rager/http/adapters/async_http.rb
@@ -96,7 +115,23 @@ files:
96
115
  - lib/rager/mesh_gen/providers/replicate.rb
97
116
  - lib/rager/operation.rb
98
117
  - lib/rager/options.rb
118
+ - lib/rager/rerank.rb
119
+ - lib/rager/rerank/options.rb
120
+ - lib/rager/rerank/providers/abstract.rb
121
+ - lib/rager/rerank/providers/cohere.rb
122
+ - lib/rager/rerank/query.rb
123
+ - lib/rager/rerank/result.rb
99
124
  - lib/rager/result.rb
125
+ - lib/rager/search.rb
126
+ - lib/rager/search/options.rb
127
+ - lib/rager/search/providers/abstract.rb
128
+ - lib/rager/search/providers/brave.rb
129
+ - lib/rager/search/result.rb
130
+ - lib/rager/template.rb
131
+ - lib/rager/template/input.rb
132
+ - lib/rager/template/options.rb
133
+ - lib/rager/template/providers/abstract.rb
134
+ - lib/rager/template/providers/erb.rb
100
135
  - lib/rager/types.rb
101
136
  - lib/rager/version.rb
102
137
  homepage: https://github.com/mvkvc/rager_ruby