langchainrb 0.15.0 → 0.15.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: dde504e05b1cbb32c857569bf71301537fed2deb468f1bdd69a7ef900a41c085
4
- data.tar.gz: '08659cddd6f0bb285e167c7a35dbd2f83c2e9bb51a69206217ea91649e99839c'
3
+ metadata.gz: a8a7ebf84076b609719daddc97e448f4d4fe987e8ee1eeaddb70df667f163d02
4
+ data.tar.gz: d52a9619b5913e8ce51563697e38841f9798e04f3caf294d7f331ff159eb70cb
5
5
  SHA512:
6
- metadata.gz: ce4dd091498659a2d8dda4b54e9e9584dc19be5f390dc5f1d98efa054a264134dc3510f2f83c65bdf23edfbd7344587b91113e69c2ea1fea2cdc157317735799
7
- data.tar.gz: a6df110aa7d96c87402164f67aadab0a97e2a62b68b7466cf630fe79dd0611a1740ae11163361eef9c98fc816f7ba12d7bfc0aa2225759cc8191f59fead8fcbd
6
+ metadata.gz: 2354d82608942a1744be426f23277b18fee508f539613327c9ed6f784d7da18f317d2266d356f3124eef93ea5052fe237f3fc639ff56db4b86060b08f16df1d2
7
+ data.tar.gz: 282873b85e832e9a872f007a5a6bf35400e22639c5c7f26ac535da4f06370f35d6de35a44d434ec81fedfcff1143a448440cf8bf76ae38e01d0ad5ec15f08dc7
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.15.1] - 2024-08-19
4
+ - Drop `to_bool` gem in favour of custom util class
5
+ - Drop `colorize` which is GPL-licensed in favour of `rainbow`
6
+ - Improve Langchain::Tool::Weather tool
7
+
3
8
  ## [0.15.0] - 2024-08-14
4
9
  - Fix Langchain::Assistant when llm is Anthropic
5
10
  - Fix GoogleGemini#chat method
@@ -135,7 +140,7 @@
135
140
  - AWS Bedrock is available as an LLM provider. Available models from AI21, Cohere, AWS, and Anthropic.
136
141
 
137
142
  ## [0.7.3] - 2023-11-08
138
- - LLM response passes through the context in RAG cases
143
+ - LLM response passes through the context in RAG cases
139
144
  - Fix gpt-4 token length validation
140
145
 
141
146
  ## [0.7.2] - 2023-11-02
@@ -180,7 +185,7 @@
180
185
 
181
186
  ## [0.6.13] - 2023-08-23
182
187
  - Add `k:` parameter to all `ask()` vector search methods
183
- - Bump Faraday to 2.x
188
+ - Bump Faraday to 2.x
184
189
 
185
190
  ## [0.6.12] - 2023-08-13
186
191
 
@@ -42,13 +42,13 @@ module Langchain
42
42
  for_class_name = for_class&.name
43
43
 
44
44
  log_line_parts = []
45
- log_line_parts << "[Langchain.rb]".colorize(color: :yellow)
45
+ log_line_parts << colorize("[Langchain.rb]", color: :yellow)
46
46
  log_line_parts << if for_class.respond_to?(:logger_options)
47
- "[#{for_class_name}]".colorize(for_class.logger_options) + ":"
47
+ colorize("[#{for_class_name}]", for_class.logger_options) + ":"
48
48
  elsif for_class_name
49
49
  "[#{for_class_name}]:"
50
50
  end
51
- log_line_parts << args.first.colorize(MESSAGE_COLOR_OPTIONS[method])
51
+ log_line_parts << colorize(args.first, MESSAGE_COLOR_OPTIONS[method])
52
52
  log_line = log_line_parts.compact.join(" ")
53
53
 
54
54
  @logger.send(
@@ -56,5 +56,11 @@ module Langchain
56
56
  log_line
57
57
  )
58
58
  end
59
+
60
+ private
61
+
62
+ def colorize(line, options)
63
+ Langchain::Utils::Colorizer.colorize(line, options)
64
+ end
59
65
  end
60
66
  end
@@ -47,7 +47,7 @@ module Langchain
47
47
  verdicts = match.captures.first
48
48
  verdicts
49
49
  .split(".")
50
- .count { |value| value.strip.to_boolean }
50
+ .count { |value| to_boolean(value.strip) }
51
51
  end
52
52
 
53
53
  def statements_verification(statements:, context:)
@@ -79,6 +79,10 @@ module Langchain
79
79
  file_path: Langchain.root.join("langchain/evals/ragas/prompts/faithfulness_statements_extraction.yml")
80
80
  )
81
81
  end
82
+
83
+ def to_boolean(value)
84
+ Langchain::Utils::ToBoolean.new.to_bool(value)
85
+ end
82
86
  end
83
87
  end
84
88
  end
@@ -7,53 +7,103 @@ module Langchain::Tool
7
7
  # Current weather data is free for 1000 calls per day (https://home.openweathermap.org/api_keys)
8
8
  # Forecast and historical data require registration with credit card, so not supported yet.
9
9
  #
10
- # Gem requirements:
11
- # gem "open-weather-ruby-client", "~> 0.3.0"
12
- # api_key: https://home.openweathermap.org/api_keys
13
- #
14
10
  # Usage:
15
11
  # weather = Langchain::Tool::Weather.new(api_key: ENV["OPEN_WEATHER_API_KEY"])
16
- # weather.execute(input: "Boston, MA; imperial")
12
+ # assistant = Langchain::Assistant.new(
13
+ # llm: llm,
14
+ # tools: [weather]
15
+ # )
17
16
  #
18
17
  class Weather
19
18
  extend Langchain::ToolDefinition
20
- include Langchain::DependencyHelper
21
19
 
22
- define_function :execute, description: "Returns current weather for a city" do
23
- property :input, type: "string", description: "Comma separated city and unit (optional: imperial, metric, or standard)", required: true
20
+ define_function :get_current_weather, description: "Returns current weather for a city" do
21
+ property :city,
22
+ type: "string",
23
+ description: "City name",
24
+ required: true
25
+ property :state_code,
26
+ type: "string",
27
+ description: "State code",
28
+ required: true
29
+ property :country_code,
30
+ type: "string",
31
+ description: "Country code",
32
+ required: false
33
+ property :units,
34
+ type: "string",
35
+ description: "Units for temperature (imperial or metric). Default: \"imperial\"",
36
+ enum: ["imperial", "metric", "standard"],
37
+ required: false
24
38
  end
25
39
 
26
- attr_reader :client, :units
40
+ def initialize(api_key:)
41
+ @api_key = api_key
42
+ end
27
43
 
28
- # Initializes the Weather tool
29
- #
30
- # @param api_key [String] Open Weather API key
31
- # @return [Langchain::Tool::Weather] Weather tool
32
- def initialize(api_key:, units: "metric")
33
- depends_on "open-weather-ruby-client"
34
- require "open-weather-ruby-client"
44
+ def get_current_weather(city:, state_code:, country_code: nil, units: "imperial")
45
+ validate_input(city: city, state_code: state_code, country_code: country_code, units: units)
35
46
 
36
- OpenWeather::Client.configure do |config|
37
- config.api_key = api_key
38
- config.user_agent = "Langchainrb Ruby Client"
39
- end
47
+ Langchain.logger.info("get_current_weather", for: self.class, city:, state_code:, country_code:, units:)
40
48
 
41
- @client = OpenWeather::Client.new
49
+ fetch_current_weather(city: city, state_code: state_code, country_code: country_code, units: units)
42
50
  end
43
51
 
44
- # Returns current weather for a city
45
- #
46
- # @param input [String] comma separated city and unit (optional: imperial, metric, or standard)
47
- # @return [String] Answer
48
- def execute(input:)
49
- Langchain.logger.info("Executing for \"#{input}\"", for: self.class)
52
+ private
53
+
54
+ def fetch_current_weather(city:, state_code:, country_code:, units:)
55
+ params = {appid: @api_key, q: [city, state_code, country_code].compact.join(","), units: units}
56
+
57
+ location_response = send_request(path: "geo/1.0/direct", params: params.except(:units))
58
+ return location_response if location_response.is_a?(String) # Error occurred
59
+
60
+ location = location_response.first
61
+ return "Location not found" unless location
62
+
63
+ params = params.merge(lat: location["lat"], lon: location["lon"]).except(:q)
64
+ weather_data = send_request(path: "data/2.5/weather", params: params)
65
+
66
+ parse_weather_response(weather_data, units)
67
+ end
50
68
 
51
- input_array = input.split(";")
52
- city, units = *input_array.map(&:strip)
69
+ def send_request(path:, params:)
70
+ uri = URI.parse("https://api.openweathermap.org/#{path}?#{URI.encode_www_form(params)}")
71
+ http = Net::HTTP.new(uri.host, uri.port)
72
+ http.use_ssl = true
53
73
 
54
- data = client.current_weather(city: city, units: units)
55
- weather = data.main.map { |key, value| "#{key} #{value}" }.join(", ")
56
- "The current weather in #{data.name} is #{weather}"
74
+ request = Net::HTTP::Get.new(uri.request_uri)
75
+ request["Content-Type"] = "application/json"
76
+
77
+ Langchain.logger.info("Sending request to OpenWeatherMap API", path: path, params: params.except(:appid))
78
+ response = http.request(request)
79
+ Langchain.logger.info("Received response from OpenWeatherMap API", status: response.code)
80
+
81
+ if response.code == "200"
82
+ JSON.parse(response.body)
83
+ else
84
+ "API request failed: #{response.code} - #{response.message}"
85
+ end
86
+ end
87
+
88
+ def validate_input(city:, state_code:, country_code:, units:)
89
+ raise ArgumentError, "City name cannot be empty" if city.to_s.strip.empty?
90
+ raise ArgumentError, "State code cannot be empty" if state_code.to_s.strip.empty?
91
+ raise ArgumentError, "Invalid units. Use \"imperial\", \"standard\" or \"metric\"" unless ["imperial", "metric", "standard"].include?(units)
92
+ end
93
+
94
+ def parse_weather_response(response, units)
95
+ temp_unit = case units
96
+ when "standard" then "K"
97
+ when "metric" then "°C"
98
+ when "imperial" then "°F"
99
+ end
100
+ speed_unit = (units == "imperial") ? "mph" : "m/s"
101
+ {
102
+ temperature: "#{response["main"]["temp"]} #{temp_unit}",
103
+ humidity: "#{response["main"]["humidity"]}%",
104
+ description: response["weather"][0]["description"],
105
+ wind_speed: "#{response["wind"]["speed"]} #{speed_unit}"
106
+ }
57
107
  end
58
108
  end
59
109
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Langchain
4
+ module Utils
5
+ class Colorizer
6
+ def self.colorize(line, options)
7
+ decorated_line = Rainbow(line)
8
+ options.each_pair.each do |modifier, value|
9
+ decorated_line = if modifier == :mode
10
+ decorated_line.public_send(value)
11
+ else
12
+ decorated_line.public_send(modifier, value)
13
+ end
14
+ end
15
+ decorated_line
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Langchain
4
+ module Utils
5
+ class ToBoolean
6
+ TRUTHABLE_STRINGS = %w[1 true t yes y]
7
+ private_constant :TRUTHABLE_STRINGS
8
+
9
+ def to_bool(value)
10
+ case value
11
+ when String
12
+ TRUTHABLE_STRINGS.include?(value.downcase)
13
+ when Integer
14
+ value == 1
15
+ when TrueClass
16
+ true
17
+ when FalseClass
18
+ false
19
+ when Symbol
20
+ to_bool(value.to_s)
21
+ else
22
+ false
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Langchain
4
- VERSION = "0.15.0"
4
+ VERSION = "0.15.1"
5
5
  end
data/lib/langchain.rb CHANGED
@@ -2,8 +2,7 @@
2
2
 
3
3
  require "logger"
4
4
  require "pathname"
5
- require "colorize"
6
- require "to_bool"
5
+ require "rainbow"
7
6
  require "zeitwerk"
8
7
  loader = Zeitwerk::Loader.for_gem
9
8
  loader.ignore("#{__dir__}/langchainrb.rb")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: langchainrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 0.15.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Bondarev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-08-14 00:00:00.000000000 Z
11
+ date: 2024-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: baran
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.1.9
27
27
  - !ruby/object:Gem::Dependency
28
- name: colorize
28
+ name: rainbow
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.1.0
33
+ version: 3.1.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.1.0
40
+ version: 3.1.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: json-schema
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,20 +80,6 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.3.0
83
- - !ruby/object:Gem::Dependency
84
- name: to_bool
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 2.0.0
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: 2.0.0
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: matrix
99
85
  requirement: !ruby/object:Gem::Requirement
@@ -472,20 +458,6 @@ dependencies:
472
458
  - - ">="
473
459
  - !ruby/object:Gem::Version
474
460
  version: '0'
475
- - !ruby/object:Gem::Dependency
476
- name: open-weather-ruby-client
477
- requirement: !ruby/object:Gem::Requirement
478
- requirements:
479
- - - "~>"
480
- - !ruby/object:Gem::Version
481
- version: 0.4.0
482
- type: :development
483
- prerelease: false
484
- version_requirements: !ruby/object:Gem::Requirement
485
- requirements:
486
- - - "~>"
487
- - !ruby/object:Gem::Version
488
- version: 0.4.0
489
461
  - !ruby/object:Gem::Dependency
490
462
  name: pg
491
463
  requirement: !ruby/object:Gem::Requirement
@@ -785,8 +757,10 @@ files:
785
757
  - lib/langchain/tool/weather.rb
786
758
  - lib/langchain/tool/wikipedia.rb
787
759
  - lib/langchain/tool_definition.rb
760
+ - lib/langchain/utils/colorizer.rb
788
761
  - lib/langchain/utils/cosine_similarity.rb
789
762
  - lib/langchain/utils/hash_transformer.rb
763
+ - lib/langchain/utils/to_boolean.rb
790
764
  - lib/langchain/vectorsearch/base.rb
791
765
  - lib/langchain/vectorsearch/chroma.rb
792
766
  - lib/langchain/vectorsearch/elasticsearch.rb