Skip to content

Commit d87a9c3

Browse files
Moving files over from the langchainrb repo
1 parent 236043e commit d87a9c3

File tree

10 files changed

+270
-22
lines changed

10 files changed

+270
-22
lines changed

.circleci/config.yml

Lines changed: 0 additions & 13 deletions
This file was deleted.

.circleci/workflows/ci.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: Tests
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- "*"
7+
push:
8+
branches:
9+
- main
10+
jobs:
11+
tests:
12+
runs-on: ubuntu-latest
13+
strategy:
14+
matrix:
15+
ruby: ["3.0", "3.1", "3.2"]
16+
17+
steps:
18+
- uses: actions/checkout@master
19+
- name: Set up Ruby
20+
uses: ruby/setup-ruby@v1
21+
with:
22+
ruby-version: ${{ matrix.ruby }}
23+
bundler: default
24+
bundler-cache: true
25+
26+
- name: Run tests
27+
run: |
28+
bundle exec rspec
29+
linters:
30+
runs-on: ubuntu-latest
31+
steps:
32+
- uses: actions/checkout@master
33+
- name: Set up Ruby
34+
uses: ruby/setup-ruby@v1
35+
with:
36+
ruby-version: 3.2
37+
bundler: default
38+
bundler-cache: true
39+
- name: StandardRb check
40+
run: bundle exec standardrb --format progress --format github --color
41+
docs:
42+
runs-on: ubuntu-latest
43+
steps:
44+
- uses: actions/checkout@master
45+
- name: Set up Ruby
46+
uses: ruby/setup-ruby@v1
47+
with:
48+
ruby-version: 3.2
49+
bundler: default
50+
bundler-cache: true
51+
- name: Build docs
52+
run: bundle exec yardoc

Gemfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@ gemspec
88
gem "rake", "~> 13.0"
99

1010
gem "rspec", "~> 3.0"
11+
12+
gem "standardrb"
13+
14+
gem "langchainrb"

Gemfile.lock

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@ GEM
99
specs:
1010
addressable (2.8.5)
1111
public_suffix (>= 2.0.2, < 6.0)
12+
ast (2.4.2)
1213
baran (0.1.9)
14+
base64 (0.1.1)
15+
byebug (11.1.3)
16+
coderay (1.1.3)
1317
colorize (0.8.1)
1418
diff-lcs (1.5.0)
19+
json (2.6.3)
1520
json-schema (4.0.0)
1621
addressable (>= 2.8)
1722
langchainrb (0.6.19)
@@ -20,11 +25,28 @@ GEM
2025
json-schema (~> 4.0.0)
2126
pragmatic_segmenter (~> 0.3.0)
2227
tiktoken_ruby (~> 0.0.5)
23-
zeitwerk (= 2.6.11)
28+
zeitwerk (~> 2.5)
29+
language_server-protocol (3.17.0.3)
30+
lint_roller (1.1.0)
31+
method_source (1.0.0)
32+
parallel (1.23.0)
33+
parser (3.2.2.4)
34+
ast (~> 2.4.1)
35+
racc
2436
pragmatic_segmenter (0.3.23)
2537
unicode
38+
pry (0.14.2)
39+
coderay (~> 1.1)
40+
method_source (~> 1.0)
41+
pry-byebug (3.10.1)
42+
byebug (~> 11.0)
43+
pry (>= 0.13, < 0.15)
2644
public_suffix (5.0.3)
45+
racc (1.7.1)
46+
rainbow (3.1.1)
2747
rake (13.0.6)
48+
regexp_parser (2.8.2)
49+
rexml (3.2.6)
2850
rspec (3.12.0)
2951
rspec-core (~> 3.12.0)
3052
rspec-expectations (~> 3.12.0)
@@ -38,17 +60,55 @@ GEM
3860
diff-lcs (>= 1.2.0, < 2.0)
3961
rspec-support (~> 3.12.0)
4062
rspec-support (3.12.1)
63+
rubocop (1.56.4)
64+
base64 (~> 0.1.1)
65+
json (~> 2.3)
66+
language_server-protocol (>= 3.17.0)
67+
parallel (~> 1.10)
68+
parser (>= 3.2.2.3)
69+
rainbow (>= 2.2.2, < 4.0)
70+
regexp_parser (>= 1.8, < 3.0)
71+
rexml (>= 3.2.5, < 4.0)
72+
rubocop-ast (>= 1.28.1, < 2.0)
73+
ruby-progressbar (~> 1.7)
74+
unicode-display_width (>= 2.4.0, < 3.0)
75+
rubocop-ast (1.29.0)
76+
parser (>= 3.2.1.0)
77+
rubocop-performance (1.19.1)
78+
rubocop (>= 1.7.0, < 2.0)
79+
rubocop-ast (>= 0.4.0)
80+
ruby-progressbar (1.13.0)
81+
standard (1.31.2)
82+
language_server-protocol (~> 3.17.0.2)
83+
lint_roller (~> 1.0)
84+
rubocop (~> 1.56.4)
85+
standard-custom (~> 1.0.0)
86+
standard-performance (~> 1.2)
87+
standard-custom (1.0.2)
88+
lint_roller (~> 1.0)
89+
rubocop (~> 1.50)
90+
standard-performance (1.2.1)
91+
lint_roller (~> 1.1)
92+
rubocop-performance (~> 1.19.1)
93+
standardrb (1.0.1)
94+
standard
4195
tiktoken_ruby (0.0.6-x86_64-darwin)
4296
unicode (0.4.4.4)
97+
unicode-display_width (2.5.0)
98+
yard (0.9.34)
4399
zeitwerk (2.6.11)
44100

45101
PLATFORMS
46102
x86_64-darwin-19
47103

48104
DEPENDENCIES
105+
langchainrb
49106
langchainrb_rails!
107+
pry-byebug (~> 3.10.0)
50108
rake (~> 13.0)
51109
rspec (~> 3.0)
110+
standardrb
111+
yard (~> 0.9.34)
52112

53113
BUNDLED WITH
54114
2.4.0

langchainrb_rails.gemspec

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,8 @@ Gem::Specification.new do |spec|
3232
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
3333
spec.require_paths = ["lib"]
3434

35-
# Uncomment to register a new dependency of your gem
3635
spec.add_dependency "langchainrb", "~> 0.6.19"
3736

38-
# For more information and examples about making a new gem, check out our
39-
# guide at: https://bundler.io/guides/creating_gem.html
37+
spec.add_development_dependency "pry-byebug", "~> 3.10.0"
38+
spec.add_development_dependency "yard", "~> 0.9.34"
4039
end

lib/langchainrb_rails.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
# frozen_string_literal: true
22

3+
require "langchain"
34
require_relative "langchainrb_rails/version"
5+
require "langchainrb_rails/railtie"
46

57
module LangchainrbRails
68
class Error < StandardError; end
7-
# Your code goes here...
9+
10+
module ActiveRecord
11+
autoload :Hooks, "langchainrb_rails/active_record/hooks"
12+
end
813
end
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# frozen_string_literal: true
2+
3+
module LangchainrbRails
4+
module ActiveRecord
5+
# This module adds the following functionality to your ActiveRecord models:
6+
# * `vectorsearch` class method to set the vector search provider
7+
# * `similarity_search` class method to search for similar texts
8+
# * `upsert_to_vectorsearch` instance method to upsert the record to the vector search provider
9+
#
10+
# Usage:
11+
# class Recipe < ActiveRecord::Base
12+
# vectorsearch provider: Langchain::Vectorsearch::Weaviate.new(
13+
# api_key: ENV["WEAVIATE_API_KEY"],
14+
# url: ENV["WEAVIATE_URL"],
15+
# index_name: "Recipes",
16+
# llm: Langchain::LLM::OpenAI.new(api_key: ENV["OPENAI_API_KEY"])
17+
# )
18+
#
19+
# after_save :upsert_to_vectorsearch
20+
#
21+
# # Overwriting how the model is serialized before it's indexed
22+
# def as_vector
23+
# [
24+
# "Title: #{title}",
25+
# "Description: #{description}",
26+
# ...
27+
# ]
28+
# .compact
29+
# .join("\n")
30+
# end
31+
# end
32+
#
33+
# Create the default schema
34+
# Recipe.class_variable_get(:@@provider).create_default_schema
35+
# Query the vector search provider
36+
# Recipe.similarity_search("carnivore dish")
37+
# Delete the default schema to start over
38+
# Recipe.class_variable_get(:@@provider).destroy_default_schema
39+
#
40+
module Hooks
41+
def self.included(base)
42+
base.extend ClassMethods
43+
end
44+
45+
# Index the text to the vector search provider
46+
# You'd typically call this method in an ActiveRecord callback
47+
#
48+
# @return [Boolean] true
49+
# @raise [Error] Indexing to vector search DB failed
50+
def upsert_to_vectorsearch
51+
if previously_new_record?
52+
self.class.class_variable_get(:@@provider).add_texts(
53+
texts: [as_vector],
54+
ids: [id]
55+
)
56+
else
57+
self.class.class_variable_get(:@@provider).update_texts(
58+
texts: [as_vector],
59+
ids: [id]
60+
)
61+
end
62+
end
63+
64+
# Used to serialize the DB record to an indexable vector text
65+
# Overwrite this method in your model to customize
66+
#
67+
# @return [String] the text representation of the model
68+
def as_vector
69+
to_json
70+
end
71+
72+
module ClassMethods
73+
# Set the vector search provider
74+
#
75+
# @param provider [Object] The `Langchain::Vectorsearch::*` instance
76+
def vectorsearch(provider:)
77+
class_variable_set(:@@provider, provider)
78+
end
79+
80+
# Search for similar texts
81+
#
82+
# @param query [String] The query to search for
83+
# @param k [Integer] The number of results to return
84+
# @return [ActiveRecord::Relation] The ActiveRecord relation
85+
def similarity_search(query, k: 1)
86+
records = class_variable_get(:@@provider).similarity_search(
87+
query: query,
88+
k: k
89+
)
90+
91+
# We use "__id" when Weaviate is the provider
92+
ids = records.map { |record| record.dig("id") || record.dig("__id") }
93+
where(id: ids)
94+
end
95+
96+
# Ask a question and return the answer
97+
#
98+
# @param question [String] The question to ask
99+
# @param k [Integer] The number of results to have in context
100+
# @yield [String] Stream responses back one String at a time
101+
# @return [String] The answer to the question
102+
def ask(question:, k: 4, &block)
103+
class_variable_get(:@@provider).ask(
104+
question: question,
105+
k: k,
106+
&block
107+
)
108+
end
109+
end
110+
end
111+
end
112+
end

lib/langchainrb_rails/railtie.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# frozen_string_literal: true
2+
3+
module LangchainrbRails
4+
class Railtie < Rails::Railtie
5+
initializer "langchain" do
6+
ActiveSupport.on_load(:active_record) do
7+
::ActiveRecord::Base.include LangchainrbRails::ActiveRecord::Hooks
8+
end
9+
end
10+
end
11+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
class Dummy
4+
include ::LangchainrbRails::ActiveRecord::Hooks
5+
end
6+
7+
RSpec.describe LangchainrbRails::ActiveRecord::Hooks do
8+
it "responds to instance methods" do
9+
expect(::Dummy.new).to respond_to(:upsert_to_vectorsearch)
10+
expect(::Dummy.new).to respond_to(:as_vector)
11+
end
12+
13+
it "responds to class method: similarity_search" do
14+
expect(::Dummy).to respond_to(:vectorsearch)
15+
expect(::Dummy).to respond_to(:similarity_search)
16+
end
17+
18+
it "responds to class method: ask" do
19+
expect(::Dummy).to respond_to(:vectorsearch)
20+
expect(::Dummy).to respond_to(:ask)
21+
end
22+
end

spec/langchainrb_rails_spec.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,4 @@
44
it "has a version number" do
55
expect(LangchainrbRails::VERSION).not_to be nil
66
end
7-
8-
it "does something useful" do
9-
expect(false).to eq(true)
10-
end
117
end

0 commit comments

Comments
 (0)