langchainrb 0.8.1 → 0.9.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 +8 -0
- data/README.md +53 -25
- data/lib/langchain/assistants/assistant.rb +199 -0
- data/lib/langchain/assistants/message.rb +58 -0
- data/lib/langchain/assistants/thread.rb +34 -0
- data/lib/langchain/chunker/markdown.rb +39 -0
- data/lib/langchain/conversation/memory.rb +1 -6
- data/lib/langchain/conversation.rb +7 -18
- data/lib/langchain/data.rb +4 -3
- data/lib/langchain/llm/ai21.rb +1 -1
- data/lib/langchain/llm/azure.rb +10 -97
- data/lib/langchain/llm/base.rb +1 -0
- data/lib/langchain/llm/cohere.rb +4 -6
- data/lib/langchain/llm/google_palm.rb +2 -0
- data/lib/langchain/llm/google_vertex_ai.rb +12 -10
- data/lib/langchain/llm/openai.rb +104 -160
- data/lib/langchain/llm/replicate.rb +0 -6
- data/lib/langchain/llm/response/anthropic_response.rb +4 -0
- data/lib/langchain/llm/response/google_palm_response.rb +4 -0
- data/lib/langchain/llm/response/ollama_response.rb +5 -1
- data/lib/langchain/llm/response/openai_response.rb +8 -0
- data/lib/langchain/loader.rb +3 -2
- data/lib/langchain/processors/markdown.rb +17 -0
- data/lib/langchain/tool/base.rb +24 -0
- data/lib/langchain/tool/google_search.rb +1 -4
- data/lib/langchain/utils/token_length/ai21_validator.rb +6 -2
- data/lib/langchain/utils/token_length/base_validator.rb +1 -1
- data/lib/langchain/utils/token_length/cohere_validator.rb +6 -2
- data/lib/langchain/utils/token_length/google_palm_validator.rb +5 -1
- data/lib/langchain/utils/token_length/openai_validator.rb +41 -0
- data/lib/langchain/vectorsearch/base.rb +2 -2
- data/lib/langchain/vectorsearch/epsilla.rb +5 -1
- data/lib/langchain/vectorsearch/pinecone.rb +2 -2
- data/lib/langchain/version.rb +1 -1
- data/lib/langchain.rb +2 -1
- metadata +10 -5
data/lib/langchain/llm/azure.rb
CHANGED
@@ -4,7 +4,7 @@ module Langchain::LLM
|
|
4
4
|
# LLM interface for Azure OpenAI Service APIs: https://learn.microsoft.com/en-us/azure/ai-services/openai/
|
5
5
|
#
|
6
6
|
# Gem requirements:
|
7
|
-
# gem "ruby-openai", "~> 6.
|
7
|
+
# gem "ruby-openai", "~> 6.3.0"
|
8
8
|
#
|
9
9
|
# Usage:
|
10
10
|
# openai = Langchain::LLM::Azure.new(api_key:, llm_options: {}, embedding_deployment_url: chat_deployment_url:)
|
@@ -34,106 +34,19 @@ module Langchain::LLM
|
|
34
34
|
@defaults = DEFAULTS.merge(default_options)
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
# @param text [String] The text to generate an embedding for
|
41
|
-
# @param params extra parameters passed to OpenAI::Client#embeddings
|
42
|
-
# @return [Langchain::LLM::OpenAIResponse] Response object
|
43
|
-
#
|
44
|
-
def embed(text:, **params)
|
45
|
-
parameters = {model: @defaults[:embeddings_model_name], input: text}
|
46
|
-
|
47
|
-
validate_max_tokens(text, parameters[:model])
|
48
|
-
|
49
|
-
response = with_api_error_handling do
|
50
|
-
embed_client.embeddings(parameters: parameters.merge(params))
|
51
|
-
end
|
52
|
-
|
53
|
-
Langchain::LLM::OpenAIResponse.new(response)
|
37
|
+
def embed(...)
|
38
|
+
@client = @embed_client
|
39
|
+
super(...)
|
54
40
|
end
|
55
41
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
# @param prompt [String] The prompt to generate a completion for
|
60
|
-
# @param params extra parameters passed to OpenAI::Client#complete
|
61
|
-
# @return [Langchain::LLM::Response::OpenaAI] Response object
|
62
|
-
#
|
63
|
-
def complete(prompt:, **params)
|
64
|
-
parameters = compose_parameters @defaults[:completion_model_name], params
|
65
|
-
|
66
|
-
parameters[:messages] = compose_chat_messages(prompt: prompt)
|
67
|
-
parameters[:max_tokens] = validate_max_tokens(parameters[:messages], parameters[:model])
|
68
|
-
|
69
|
-
response = with_api_error_handling do
|
70
|
-
chat_client.chat(parameters: parameters)
|
71
|
-
end
|
72
|
-
|
73
|
-
Langchain::LLM::OpenAIResponse.new(response)
|
42
|
+
def complete(...)
|
43
|
+
@client = @chat_client
|
44
|
+
super(...)
|
74
45
|
end
|
75
46
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
# == Examples
|
80
|
-
#
|
81
|
-
# # simplest case, just give a prompt
|
82
|
-
# openai.chat prompt: "When was Ruby first released?"
|
83
|
-
#
|
84
|
-
# # prompt plus some context about how to respond
|
85
|
-
# openai.chat context: "You are RubyGPT, a helpful chat bot for helping people learn Ruby", prompt: "Does Ruby have a REPL like IPython?"
|
86
|
-
#
|
87
|
-
# # full control over messages that get sent, equivilent to the above
|
88
|
-
# openai.chat messages: [
|
89
|
-
# {
|
90
|
-
# role: "system",
|
91
|
-
# content: "You are RubyGPT, a helpful chat bot for helping people learn Ruby", prompt: "Does Ruby have a REPL like IPython?"
|
92
|
-
# },
|
93
|
-
# {
|
94
|
-
# role: "user",
|
95
|
-
# content: "When was Ruby first released?"
|
96
|
-
# }
|
97
|
-
# ]
|
98
|
-
#
|
99
|
-
# # few-short prompting with examples
|
100
|
-
# openai.chat prompt: "When was factory_bot released?",
|
101
|
-
# examples: [
|
102
|
-
# {
|
103
|
-
# role: "user",
|
104
|
-
# content: "When was Ruby on Rails released?"
|
105
|
-
# }
|
106
|
-
# {
|
107
|
-
# role: "assistant",
|
108
|
-
# content: "2004"
|
109
|
-
# },
|
110
|
-
# ]
|
111
|
-
#
|
112
|
-
# @param prompt [String] The prompt to generate a chat completion for
|
113
|
-
# @param messages [Array<Hash>] The messages that have been sent in the conversation
|
114
|
-
# @param context [String] An initial context to provide as a system message, ie "You are RubyGPT, a helpful chat bot for helping people learn Ruby"
|
115
|
-
# @param examples [Array<Hash>] Examples of messages to provide to the model. Useful for Few-Shot Prompting
|
116
|
-
# @param options [Hash] extra parameters passed to OpenAI::Client#chat
|
117
|
-
# @yield [Hash] Stream responses back one token at a time
|
118
|
-
# @return [Langchain::LLM::OpenAIResponse] Response object
|
119
|
-
#
|
120
|
-
def chat(prompt: "", messages: [], context: "", examples: [], **options, &block)
|
121
|
-
raise ArgumentError.new(":prompt or :messages argument is expected") if prompt.empty? && messages.empty?
|
122
|
-
|
123
|
-
parameters = compose_parameters @defaults[:chat_completion_model_name], options, &block
|
124
|
-
parameters[:messages] = compose_chat_messages(prompt: prompt, messages: messages, context: context, examples: examples)
|
125
|
-
|
126
|
-
if functions
|
127
|
-
parameters[:functions] = functions
|
128
|
-
else
|
129
|
-
parameters[:max_tokens] = validate_max_tokens(parameters[:messages], parameters[:model])
|
130
|
-
end
|
131
|
-
|
132
|
-
response = with_api_error_handling { chat_client.chat(parameters: parameters) }
|
133
|
-
|
134
|
-
return if block
|
135
|
-
|
136
|
-
Langchain::LLM::OpenAIResponse.new(response)
|
47
|
+
def chat(...)
|
48
|
+
@client = @chat_client
|
49
|
+
super(...)
|
137
50
|
end
|
138
51
|
end
|
139
52
|
end
|
data/lib/langchain/llm/base.rb
CHANGED
@@ -11,6 +11,7 @@ module Langchain::LLM
|
|
11
11
|
# - {Langchain::LLM::Azure}
|
12
12
|
# - {Langchain::LLM::Cohere}
|
13
13
|
# - {Langchain::LLM::GooglePalm}
|
14
|
+
# - {Langchain::LLM::GoogleVertexAi}
|
14
15
|
# - {Langchain::LLM::HuggingFace}
|
15
16
|
# - {Langchain::LLM::LlamaCpp}
|
16
17
|
# - {Langchain::LLM::OpenAI}
|
data/lib/langchain/llm/cohere.rb
CHANGED
@@ -62,17 +62,15 @@ module Langchain::LLM
|
|
62
62
|
|
63
63
|
default_params.merge!(params)
|
64
64
|
|
65
|
-
default_params[:max_tokens] = Langchain::Utils::TokenLength::CohereValidator.validate_max_tokens!(prompt, default_params[:model], client)
|
65
|
+
default_params[:max_tokens] = Langchain::Utils::TokenLength::CohereValidator.validate_max_tokens!(prompt, default_params[:model], llm: client)
|
66
66
|
|
67
67
|
response = client.generate(**default_params)
|
68
68
|
Langchain::LLM::CohereResponse.new response, model: @defaults[:completion_model_name]
|
69
69
|
end
|
70
70
|
|
71
|
-
#
|
72
|
-
def chat
|
73
|
-
|
74
|
-
::Langchain::Conversation::Response.new(response_text)
|
75
|
-
end
|
71
|
+
# TODO: Implement chat method: https://github.com/andreibondarev/cohere-ruby/issues/11
|
72
|
+
# def chat
|
73
|
+
# end
|
76
74
|
|
77
75
|
# Generate a summary in English for a given text
|
78
76
|
#
|
@@ -21,6 +21,9 @@ module Langchain::LLM
|
|
21
21
|
embeddings_model_name: "textembedding-gecko"
|
22
22
|
}.freeze
|
23
23
|
|
24
|
+
# TODO: Implement token length validation
|
25
|
+
# LENGTH_VALIDATOR = Langchain::Utils::TokenLength::...
|
26
|
+
|
24
27
|
# Google Cloud has a project id and a specific region of deployment.
|
25
28
|
# For GenAI-related things, a safe choice is us-central1.
|
26
29
|
attr_reader :project_id, :client, :region
|
@@ -135,15 +138,14 @@ module Langchain::LLM
|
|
135
138
|
)
|
136
139
|
end
|
137
140
|
|
138
|
-
def chat(...)
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
141
|
+
# def chat(...)
|
142
|
+
# https://cloud.google.com/vertex-ai/docs/samples/aiplatform-sdk-chathat
|
143
|
+
# Chat params: https://cloud.google.com/vertex-ai/docs/samples/aiplatform-sdk-chat
|
144
|
+
# \"temperature\": 0.3,\n"
|
145
|
+
# + " \"maxDecodeSteps\": 200,\n"
|
146
|
+
# + " \"topP\": 0.8,\n"
|
147
|
+
# + " \"topK\": 40\n"
|
148
|
+
# + "}";
|
149
|
+
# end
|
148
150
|
end
|
149
151
|
end
|
data/lib/langchain/llm/openai.rb
CHANGED
@@ -4,156 +4,170 @@ module Langchain::LLM
|
|
4
4
|
# LLM interface for OpenAI APIs: https://platform.openai.com/overview
|
5
5
|
#
|
6
6
|
# Gem requirements:
|
7
|
-
# gem "ruby-openai", "~> 6.
|
7
|
+
# gem "ruby-openai", "~> 6.3.0"
|
8
8
|
#
|
9
9
|
# Usage:
|
10
|
-
# openai = Langchain::LLM::OpenAI.new(
|
11
|
-
#
|
10
|
+
# openai = Langchain::LLM::OpenAI.new(
|
11
|
+
# api_key: ENV["OPENAI_API_KEY"],
|
12
|
+
# llm_options: {},
|
13
|
+
# default_options: {}
|
14
|
+
# )
|
12
15
|
class OpenAI < Base
|
13
16
|
DEFAULTS = {
|
14
17
|
n: 1,
|
15
18
|
temperature: 0.0,
|
16
|
-
completion_model_name: "gpt-3.5-turbo",
|
17
19
|
chat_completion_model_name: "gpt-3.5-turbo",
|
18
20
|
embeddings_model_name: "text-embedding-ada-002",
|
19
21
|
dimension: 1536
|
20
22
|
}.freeze
|
21
23
|
|
22
|
-
LEGACY_COMPLETION_MODELS = %w[
|
23
|
-
ada
|
24
|
-
babbage
|
25
|
-
curie
|
26
|
-
davinci
|
27
|
-
].freeze
|
28
|
-
|
29
24
|
LENGTH_VALIDATOR = Langchain::Utils::TokenLength::OpenAIValidator
|
30
25
|
|
31
|
-
|
26
|
+
attr_reader :defaults
|
32
27
|
|
28
|
+
# Initialize an OpenAI LLM instance
|
29
|
+
#
|
30
|
+
# @param api_key [String] The API key to use
|
31
|
+
# @param client_options [Hash] Options to pass to the OpenAI::Client constructor
|
33
32
|
def initialize(api_key:, llm_options: {}, default_options: {})
|
34
33
|
depends_on "ruby-openai", req: "openai"
|
35
34
|
|
36
35
|
@client = ::OpenAI::Client.new(access_token: api_key, **llm_options)
|
36
|
+
|
37
37
|
@defaults = DEFAULTS.merge(default_options)
|
38
38
|
end
|
39
39
|
|
40
|
-
#
|
41
40
|
# Generate an embedding for a given text
|
42
41
|
#
|
43
42
|
# @param text [String] The text to generate an embedding for
|
44
|
-
# @param
|
43
|
+
# @param model [String] ID of the model to use
|
44
|
+
# @param encoding_format [String] The format to return the embeddings in. Can be either float or base64.
|
45
|
+
# @param user [String] A unique identifier representing your end-user
|
45
46
|
# @return [Langchain::LLM::OpenAIResponse] Response object
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
def embed(
|
48
|
+
text:,
|
49
|
+
model: defaults[:embeddings_model_name],
|
50
|
+
encoding_format: nil,
|
51
|
+
user: nil
|
52
|
+
)
|
53
|
+
raise ArgumentError.new("text argument is required") if text.empty?
|
54
|
+
raise ArgumentError.new("model argument is required") if model.empty?
|
55
|
+
raise ArgumentError.new("encoding_format must be either float or base64") if encoding_format && %w[float base64].include?(encoding_format)
|
56
|
+
|
57
|
+
parameters = {
|
58
|
+
input: text,
|
59
|
+
model: model
|
60
|
+
}
|
61
|
+
parameters[:encoding_format] = encoding_format if encoding_format
|
62
|
+
parameters[:user] = user if user
|
49
63
|
|
50
64
|
validate_max_tokens(text, parameters[:model])
|
51
65
|
|
52
66
|
response = with_api_error_handling do
|
53
|
-
client.embeddings(parameters: parameters
|
67
|
+
client.embeddings(parameters: parameters)
|
54
68
|
end
|
55
69
|
|
56
70
|
Langchain::LLM::OpenAIResponse.new(response)
|
57
71
|
end
|
58
72
|
|
59
|
-
#
|
73
|
+
# rubocop:disable Style/ArgumentsForwarding
|
60
74
|
# Generate a completion for a given prompt
|
61
75
|
#
|
62
76
|
# @param prompt [String] The prompt to generate a completion for
|
63
|
-
# @param params
|
64
|
-
# @return [Langchain::LLM::
|
65
|
-
#
|
77
|
+
# @param params [Hash] The parameters to pass to the `chat()` method
|
78
|
+
# @return [Langchain::LLM::OpenAIResponse] Response object
|
66
79
|
def complete(prompt:, **params)
|
67
|
-
|
68
|
-
|
69
|
-
return legacy_complete(prompt, parameters) if is_legacy_model?(parameters[:model])
|
70
|
-
|
71
|
-
parameters[:messages] = compose_chat_messages(prompt: prompt)
|
72
|
-
parameters[:max_tokens] = validate_max_tokens(parameters[:messages], parameters[:model], parameters[:max_tokens])
|
73
|
-
|
74
|
-
response = with_api_error_handling do
|
75
|
-
client.chat(parameters: parameters)
|
80
|
+
if params[:stop_sequences]
|
81
|
+
params[:stop] = params.delete(:stop_sequences)
|
76
82
|
end
|
77
|
-
|
78
|
-
|
83
|
+
# Should we still accept the `messages: []` parameter here?
|
84
|
+
messages = [{role: "user", content: prompt}]
|
85
|
+
chat(messages: messages, **params)
|
79
86
|
end
|
87
|
+
# rubocop:enable Style/ArgumentsForwarding
|
80
88
|
|
81
|
-
#
|
82
89
|
# Generate a chat completion for a given prompt or messages.
|
83
90
|
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
parameters =
|
129
|
-
parameters[:
|
91
|
+
# @param messages [Array<Hash>] List of messages comprising the conversation so far
|
92
|
+
# @param model [String] ID of the model to use
|
93
|
+
def chat(
|
94
|
+
messages: [],
|
95
|
+
model: defaults[:chat_completion_model_name],
|
96
|
+
frequency_penalty: nil,
|
97
|
+
logit_bias: nil,
|
98
|
+
logprobs: nil,
|
99
|
+
top_logprobs: nil,
|
100
|
+
max_tokens: nil,
|
101
|
+
n: defaults[:n],
|
102
|
+
presence_penalty: nil,
|
103
|
+
response_format: nil,
|
104
|
+
seed: nil,
|
105
|
+
stop: nil,
|
106
|
+
stream: nil,
|
107
|
+
temperature: defaults[:temperature],
|
108
|
+
top_p: nil,
|
109
|
+
tools: [],
|
110
|
+
tool_choice: nil,
|
111
|
+
user: nil,
|
112
|
+
&block
|
113
|
+
)
|
114
|
+
raise ArgumentError.new("messages argument is required") if messages.empty?
|
115
|
+
raise ArgumentError.new("model argument is required") if model.empty?
|
116
|
+
raise ArgumentError.new("'tool_choice' is only allowed when 'tools' are specified.") if tool_choice && tools.empty?
|
117
|
+
|
118
|
+
parameters = {
|
119
|
+
messages: messages,
|
120
|
+
model: model
|
121
|
+
}
|
122
|
+
parameters[:frequency_penalty] = frequency_penalty if frequency_penalty
|
123
|
+
parameters[:logit_bias] = logit_bias if logit_bias
|
124
|
+
parameters[:logprobs] = logprobs if logprobs
|
125
|
+
parameters[:top_logprobs] = top_logprobs if top_logprobs
|
126
|
+
# TODO: Fix max_tokens validation to account for tools/functions
|
127
|
+
parameters[:max_tokens] = max_tokens if max_tokens # || validate_max_tokens(parameters[:messages], parameters[:model])
|
128
|
+
parameters[:n] = n if n
|
129
|
+
parameters[:presence_penalty] = presence_penalty if presence_penalty
|
130
|
+
parameters[:response_format] = response_format if response_format
|
131
|
+
parameters[:seed] = seed if seed
|
132
|
+
parameters[:stop] = stop if stop
|
133
|
+
parameters[:stream] = stream if stream
|
134
|
+
parameters[:temperature] = temperature if temperature
|
135
|
+
parameters[:top_p] = top_p if top_p
|
136
|
+
parameters[:tools] = tools if tools.any?
|
137
|
+
parameters[:tool_choice] = tool_choice if tool_choice
|
138
|
+
parameters[:user] = user if user
|
139
|
+
|
140
|
+
# TODO: Clean this part up
|
141
|
+
if block
|
142
|
+
@response_chunks = []
|
143
|
+
parameters[:stream] = proc do |chunk, _bytesize|
|
144
|
+
chunk_content = chunk.dig("choices", 0)
|
145
|
+
@response_chunks << chunk
|
146
|
+
yield chunk_content
|
147
|
+
end
|
148
|
+
end
|
130
149
|
|
131
|
-
|
132
|
-
parameters
|
133
|
-
else
|
134
|
-
parameters[:max_tokens] = validate_max_tokens(parameters[:messages], parameters[:model], parameters[:max_tokens])
|
150
|
+
response = with_api_error_handling do
|
151
|
+
client.chat(parameters: parameters)
|
135
152
|
end
|
136
153
|
|
137
|
-
response = with_api_error_handling { client.chat(parameters: parameters) }
|
138
154
|
response = response_from_chunks if block
|
139
155
|
reset_response_chunks
|
156
|
+
|
140
157
|
Langchain::LLM::OpenAIResponse.new(response)
|
141
158
|
end
|
142
159
|
|
143
|
-
#
|
144
160
|
# Generate a summary for a given text
|
145
161
|
#
|
146
162
|
# @param text [String] The text to generate a summary for
|
147
163
|
# @return [String] The summary
|
148
|
-
#
|
149
164
|
def summarize(text:)
|
150
165
|
prompt_template = Langchain::Prompt.load_from_path(
|
151
166
|
file_path: Langchain.root.join("langchain/llm/prompts/summarize_template.yaml")
|
152
167
|
)
|
153
168
|
prompt = prompt_template.format(text: text)
|
154
169
|
|
155
|
-
complete(prompt: prompt
|
156
|
-
# Should this return a Langchain::LLM::OpenAIResponse as well?
|
170
|
+
complete(prompt: prompt)
|
157
171
|
end
|
158
172
|
|
159
173
|
private
|
@@ -164,71 +178,6 @@ module Langchain::LLM
|
|
164
178
|
@response_chunks = []
|
165
179
|
end
|
166
180
|
|
167
|
-
def is_legacy_model?(model)
|
168
|
-
LEGACY_COMPLETION_MODELS.any? { |legacy_model| model.include?(legacy_model) }
|
169
|
-
end
|
170
|
-
|
171
|
-
def legacy_complete(prompt, parameters)
|
172
|
-
Langchain.logger.warn "DEPRECATION WARNING: The model #{parameters[:model]} is deprecated. Please use gpt-3.5-turbo instead. Details: https://platform.openai.com/docs/deprecations/2023-07-06-gpt-and-embeddings"
|
173
|
-
|
174
|
-
parameters[:prompt] = prompt
|
175
|
-
parameters[:max_tokens] = validate_max_tokens(prompt, parameters[:model])
|
176
|
-
|
177
|
-
response = with_api_error_handling do
|
178
|
-
client.completions(parameters: parameters)
|
179
|
-
end
|
180
|
-
response.dig("choices", 0, "text")
|
181
|
-
end
|
182
|
-
|
183
|
-
def compose_parameters(model, params, &block)
|
184
|
-
default_params = {model: model, temperature: @defaults[:temperature], n: @defaults[:n]}
|
185
|
-
default_params[:stop] = params.delete(:stop_sequences) if params[:stop_sequences]
|
186
|
-
parameters = default_params.merge(params)
|
187
|
-
|
188
|
-
if block
|
189
|
-
@response_chunks = []
|
190
|
-
parameters[:stream] = proc do |chunk, _bytesize|
|
191
|
-
chunk_content = chunk.dig("choices", 0)
|
192
|
-
@response_chunks << chunk
|
193
|
-
yield chunk_content
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
parameters
|
198
|
-
end
|
199
|
-
|
200
|
-
def compose_chat_messages(prompt:, messages: [], context: "", examples: [])
|
201
|
-
history = []
|
202
|
-
|
203
|
-
history.concat transform_messages(examples) unless examples.empty?
|
204
|
-
|
205
|
-
history.concat transform_messages(messages) unless messages.empty?
|
206
|
-
|
207
|
-
unless context.nil? || context.empty?
|
208
|
-
history.reject! { |message| message[:role] == "system" }
|
209
|
-
history.prepend({role: "system", content: context})
|
210
|
-
end
|
211
|
-
|
212
|
-
unless prompt.empty?
|
213
|
-
if history.last && history.last[:role] == "user"
|
214
|
-
history.last[:content] += "\n#{prompt}"
|
215
|
-
else
|
216
|
-
history.append({role: "user", content: prompt})
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
history
|
221
|
-
end
|
222
|
-
|
223
|
-
def transform_messages(messages)
|
224
|
-
messages.map do |message|
|
225
|
-
{
|
226
|
-
role: message[:role],
|
227
|
-
content: message[:content]
|
228
|
-
}
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
181
|
def with_api_error_handling
|
233
182
|
response = yield
|
234
183
|
return if response.empty?
|
@@ -239,12 +188,7 @@ module Langchain::LLM
|
|
239
188
|
end
|
240
189
|
|
241
190
|
def validate_max_tokens(messages, model, max_tokens = nil)
|
242
|
-
LENGTH_VALIDATOR.validate_max_tokens!(messages, model, max_tokens: max_tokens)
|
243
|
-
end
|
244
|
-
|
245
|
-
def extract_response(response)
|
246
|
-
results = response.dig("choices").map { |choice| choice.dig("message", "content") }
|
247
|
-
(results.size == 1) ? results.first : results
|
191
|
+
LENGTH_VALIDATOR.validate_max_tokens!(messages, model, max_tokens: max_tokens, llm: self)
|
248
192
|
end
|
249
193
|
|
250
194
|
def response_from_chunks
|
@@ -77,12 +77,6 @@ module Langchain::LLM
|
|
77
77
|
Langchain::LLM::ReplicateResponse.new(response, model: @defaults[:completion_model_name])
|
78
78
|
end
|
79
79
|
|
80
|
-
# Cohere does not have a dedicated chat endpoint, so instead we call `complete()`
|
81
|
-
def chat(...)
|
82
|
-
response_text = complete(...)
|
83
|
-
::Langchain::Conversation::Response.new(response_text)
|
84
|
-
end
|
85
|
-
|
86
80
|
#
|
87
81
|
# Generate a summary for a given text
|
88
82
|
#
|
@@ -8,7 +8,7 @@ module Langchain::LLM
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def completion
|
11
|
-
|
11
|
+
completions.first
|
12
12
|
end
|
13
13
|
|
14
14
|
def completions
|
@@ -22,5 +22,9 @@ module Langchain::LLM
|
|
22
22
|
def embeddings
|
23
23
|
[raw_response&.dig("embedding")]
|
24
24
|
end
|
25
|
+
|
26
|
+
def role
|
27
|
+
"assistant"
|
28
|
+
end
|
25
29
|
end
|
26
30
|
end
|
@@ -16,10 +16,18 @@ module Langchain::LLM
|
|
16
16
|
completions&.dig(0, "message", "content")
|
17
17
|
end
|
18
18
|
|
19
|
+
def role
|
20
|
+
completions&.dig(0, "message", "role")
|
21
|
+
end
|
22
|
+
|
19
23
|
def chat_completion
|
20
24
|
completion
|
21
25
|
end
|
22
26
|
|
27
|
+
def tool_calls
|
28
|
+
chat_completions&.dig(0, "message", "tool_calls")
|
29
|
+
end
|
30
|
+
|
23
31
|
def embedding
|
24
32
|
embeddings&.first
|
25
33
|
end
|
data/lib/langchain/loader.rb
CHANGED
@@ -37,9 +37,10 @@ module Langchain
|
|
37
37
|
# @param path [String | Pathname] path to file or URL
|
38
38
|
# @param options [Hash] options passed to the processor class used to process the data
|
39
39
|
# @return [Langchain::Loader] loader instance
|
40
|
-
def initialize(path, options = {})
|
40
|
+
def initialize(path, options = {}, chunker: Langchain::Chunker::Text)
|
41
41
|
@options = options
|
42
42
|
@path = path
|
43
|
+
@chunker = chunker
|
43
44
|
end
|
44
45
|
|
45
46
|
# Is the path a URL?
|
@@ -112,7 +113,7 @@ module Langchain
|
|
112
113
|
processor_klass.new(@options).parse(@raw_data)
|
113
114
|
end
|
114
115
|
|
115
|
-
Langchain::Data.new(result)
|
116
|
+
Langchain::Data.new(result, source: @options[:source], chunker: @chunker)
|
116
117
|
end
|
117
118
|
|
118
119
|
def processor_klass
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain
|
4
|
+
module Processors
|
5
|
+
class Markdown < Base
|
6
|
+
EXTENSIONS = [".markdown", ".md"]
|
7
|
+
CONTENT_TYPES = ["text/markdown"]
|
8
|
+
|
9
|
+
# Parse the document and return the text
|
10
|
+
# @param [File] data
|
11
|
+
# @return [String]
|
12
|
+
def parse(data)
|
13
|
+
data.read
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|