durable-llm 0.1.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 +7 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +20 -0
- data/Gemfile.lock +102 -0
- data/LICENSE.txt +21 -0
- data/README.md +96 -0
- data/Rakefile +16 -0
- data/enterprise/GET_ENTERPRISE.md +40 -0
- data/lib/durable/llm/cli.rb +122 -0
- data/lib/durable/llm/client.rb +32 -0
- data/lib/durable/llm/configuration.rb +63 -0
- data/lib/durable/llm/errors.rb +33 -0
- data/lib/durable/llm/providers/anthropic.rb +164 -0
- data/lib/durable/llm/providers/base.rb +49 -0
- data/lib/durable/llm/providers/groq.rb +177 -0
- data/lib/durable/llm/providers/huggingface.rb +93 -0
- data/lib/durable/llm/providers/openai.rb +212 -0
- data/lib/durable/llm/providers.rb +43 -0
- data/lib/durable/llm/version.rb +7 -0
- data/lib/durable/llm.rb +23 -0
- data/sig/durable/llm.rbs +6 -0
- metadata +208 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3ce04ccf2ee305fcba4a22e53473f9428f32dd869577d85af7923d15cfbd63b5
|
4
|
+
data.tar.gz: bcd7a736b0ad7d199f9ab836e84b6ff7f077da0d172385ded64b24dde82da984
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d1786c13db8285c512d5fa0f83541f349f13d54e0bdc968c7aa1e94caf2c9226c9ba1c83f9525d8718cf2a3315674e9ef45322c969ccee1efc984086440a6d05
|
7
|
+
data.tar.gz: 97d7ecccb4c6ae9b4bc6e2ed321af0c22899703044f8e8c75684b306ce8e88b241b0447ffdca2afa3dcb44a8f36f8a67c780de016c0594d92eb9f8898a4ad538
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in durable-llm.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
gem "rake", "~> 13.0"
|
9
|
+
|
10
|
+
gem "minitest", "~> 5.0"
|
11
|
+
|
12
|
+
gem "rubocop", "~> 1.21"
|
13
|
+
|
14
|
+
gem "ruby-openai", "~> 7.1"
|
15
|
+
|
16
|
+
gem "thor", "~> 1.3"
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
gem "webmock", "~> 3.24"
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
durable-llm (0.1.0)
|
5
|
+
faraday (~> 2.0)
|
6
|
+
highline (~> 3.1)
|
7
|
+
json (~> 2.6)
|
8
|
+
thor (~> 1.3)
|
9
|
+
zeitwerk (~> 2.6)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
addressable (2.8.7)
|
15
|
+
public_suffix (>= 2.0.2, < 7.0)
|
16
|
+
ast (2.4.2)
|
17
|
+
base64 (0.2.0)
|
18
|
+
bigdecimal (3.1.8)
|
19
|
+
crack (1.0.0)
|
20
|
+
bigdecimal
|
21
|
+
rexml
|
22
|
+
dotenv (2.8.1)
|
23
|
+
event_stream_parser (1.0.0)
|
24
|
+
faraday (2.12.0)
|
25
|
+
faraday-net_http (>= 2.0, < 3.4)
|
26
|
+
json
|
27
|
+
logger
|
28
|
+
faraday-multipart (1.0.4)
|
29
|
+
multipart-post (~> 2)
|
30
|
+
faraday-net_http (3.3.0)
|
31
|
+
net-http
|
32
|
+
hashdiff (1.1.1)
|
33
|
+
highline (3.1.1)
|
34
|
+
reline
|
35
|
+
io-console (0.7.2)
|
36
|
+
json (2.7.2)
|
37
|
+
language_server-protocol (3.17.0.3)
|
38
|
+
logger (1.6.1)
|
39
|
+
minitest (5.25.1)
|
40
|
+
mocha (2.4.5)
|
41
|
+
ruby2_keywords (>= 0.0.5)
|
42
|
+
multipart-post (2.4.1)
|
43
|
+
net-http (0.4.1)
|
44
|
+
uri
|
45
|
+
parallel (1.26.3)
|
46
|
+
parser (3.3.5.0)
|
47
|
+
ast (~> 2.4.1)
|
48
|
+
racc
|
49
|
+
public_suffix (6.0.1)
|
50
|
+
racc (1.8.1)
|
51
|
+
rainbow (3.1.1)
|
52
|
+
rake (13.2.1)
|
53
|
+
regexp_parser (2.9.2)
|
54
|
+
reline (0.5.10)
|
55
|
+
io-console (~> 0.5)
|
56
|
+
rexml (3.3.8)
|
57
|
+
rubocop (1.66.1)
|
58
|
+
json (~> 2.3)
|
59
|
+
language_server-protocol (>= 3.17.0)
|
60
|
+
parallel (~> 1.10)
|
61
|
+
parser (>= 3.3.0.2)
|
62
|
+
rainbow (>= 2.2.2, < 4.0)
|
63
|
+
regexp_parser (>= 2.4, < 3.0)
|
64
|
+
rubocop-ast (>= 1.32.2, < 2.0)
|
65
|
+
ruby-progressbar (~> 1.7)
|
66
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
67
|
+
rubocop-ast (1.32.3)
|
68
|
+
parser (>= 3.3.1.0)
|
69
|
+
ruby-openai (7.1.0)
|
70
|
+
event_stream_parser (>= 0.3.0, < 2.0.0)
|
71
|
+
faraday (>= 1)
|
72
|
+
faraday-multipart (>= 1)
|
73
|
+
ruby-progressbar (1.13.0)
|
74
|
+
ruby2_keywords (0.0.5)
|
75
|
+
thor (1.3.2)
|
76
|
+
unicode-display_width (2.6.0)
|
77
|
+
uri (0.13.1)
|
78
|
+
vcr (6.3.1)
|
79
|
+
base64
|
80
|
+
webmock (3.24.0)
|
81
|
+
addressable (>= 2.8.0)
|
82
|
+
crack (>= 0.3.2)
|
83
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
84
|
+
zeitwerk (2.6.18)
|
85
|
+
|
86
|
+
PLATFORMS
|
87
|
+
x86_64-linux
|
88
|
+
|
89
|
+
DEPENDENCIES
|
90
|
+
dotenv (~> 2.8)
|
91
|
+
durable-llm!
|
92
|
+
minitest (~> 5.0)
|
93
|
+
mocha (~> 2.1)
|
94
|
+
rake (~> 13.0)
|
95
|
+
rubocop (~> 1.21)
|
96
|
+
ruby-openai (~> 7.1)
|
97
|
+
thor (~> 1.3)
|
98
|
+
vcr (~> 6.0)
|
99
|
+
webmock (~> 3.24)
|
100
|
+
|
101
|
+
BUNDLED WITH
|
102
|
+
2.4.10
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 Durable Programming Team
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# Durable-LLM
|
2
|
+
|
3
|
+
Durable-LLM is a Ruby gem providing a unified interface for interacting with multiple Large Language Model APIs. It simplifies the integration of AI capabilities into Ruby applications by offering a consistent way to access various LLM providers.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'durable-llm'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
```
|
16
|
+
$ bundle install
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
```
|
22
|
+
$ gem install durable-llm
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
Here's a basic example of how to use Durable-LLM:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'durable-llm'
|
31
|
+
|
32
|
+
client = Durable::Llm::Client.new(:openai, api_key: 'your-api-key')
|
33
|
+
|
34
|
+
response = client.completion(
|
35
|
+
model: 'gpt-3.5-turbo',
|
36
|
+
messages: [{ role: 'user', content: 'Hello, how are you?' }]
|
37
|
+
)
|
38
|
+
|
39
|
+
puts response.choices.first.message.content
|
40
|
+
|
41
|
+
```
|
42
|
+
|
43
|
+
## Features
|
44
|
+
|
45
|
+
- Unified interface for multiple LLM providers
|
46
|
+
- Consistent input/output format across different models
|
47
|
+
- Error handling and retries
|
48
|
+
- Streaming support
|
49
|
+
- Customizable timeout and request options
|
50
|
+
|
51
|
+
## Supported Providers
|
52
|
+
|
53
|
+
- OpenAI
|
54
|
+
- Anthropic
|
55
|
+
- Cohere
|
56
|
+
- AI21
|
57
|
+
- (More providers to be added)
|
58
|
+
|
59
|
+
## Configuration
|
60
|
+
|
61
|
+
You can configure Durable-LLM globally or on a per-request basis:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
Durable::Llm.configure do |config|
|
65
|
+
config.default_provider = :openai
|
66
|
+
config.openai.api_key = 'your-openai-api-key'
|
67
|
+
config.anthropic.api_key = 'your-anthropic-api-key'
|
68
|
+
# Add other provider configurations as needed
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
## Error Handling
|
73
|
+
|
74
|
+
Durable-LLM provides a unified error handling system:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
begin
|
78
|
+
response = client.completion(model: 'gpt-3.5-turbo', messages: [...])
|
79
|
+
rescue Durable::Llm::APIError => e
|
80
|
+
puts "API Error: #{e.message}"
|
81
|
+
rescue Durable::Llm::RateLimitError => e
|
82
|
+
puts "Rate Limit Exceeded: #{e.message}"
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
## Acknowledgements
|
87
|
+
|
88
|
+
Thank you to the lite-llm and llm.datasette.io projects for their hard work, which was invaluable to this project. The dllm command line tool is patterned after the llm tool, though not as full-featured (yet).
|
89
|
+
|
90
|
+
## Contributing
|
91
|
+
|
92
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/durableprogramming/durable-llm.
|
93
|
+
|
94
|
+
## License
|
95
|
+
|
96
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rake/testtask"
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << "test"
|
8
|
+
t.libs << "lib"
|
9
|
+
t.test_files = FileList["test/**/test_*.rb"]
|
10
|
+
end
|
11
|
+
|
12
|
+
require "rubocop/rake_task"
|
13
|
+
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
|
16
|
+
task default: %i[test rubocop]
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Enterprise Features for Durable-LLM
|
2
|
+
|
3
|
+
Durable-LLM offers customized enterprise-grade options designed to meet the needs of large-scale organizations and mission-critical applications. Custom-fit Durable-LLM solutions enhance security, scalability, and reliability for enterprise users.
|
4
|
+
|
5
|
+
## Advanced Security
|
6
|
+
|
7
|
+
- **End-to-End Encryption**: All communications with LLM providers are encrypted using industry-standard protocols.
|
8
|
+
- **Role-Based Access Control (RBAC)**: Granular control over user permissions and access to different LLM providers and models.
|
9
|
+
- **Audit Logging**: Comprehensive logging of all API calls and user actions for compliance and security purposes.
|
10
|
+
|
11
|
+
## High Availability and Scalability
|
12
|
+
|
13
|
+
- **Load Balancing**: Automatically distribute requests across multiple LLM providers to ensure optimal performance and reliability.
|
14
|
+
- **Failover Mechanisms**: Seamlessly switch between providers in case of outages or performance issues.
|
15
|
+
- **Horizontal Scaling**: Easily scale your Durable-LLM deployment across multiple servers to handle increased load.
|
16
|
+
|
17
|
+
## Advanced Monitoring and Analytics
|
18
|
+
|
19
|
+
- **Real-time Metrics**: Monitor usage, latency, and error rates across all integrated LLM providers.
|
20
|
+
- **Custom Dashboards**: Create tailored dashboards to visualize key performance indicators and usage patterns.
|
21
|
+
- **Alerting System**: Set up custom alerts for various thresholds and events to proactively manage your LLM infrastructure.
|
22
|
+
|
23
|
+
## Customization and Integration
|
24
|
+
|
25
|
+
- **Custom Model Integration**: Easily integrate your own fine-tuned models or proprietary LLMs.
|
26
|
+
- **API Customization**: Tailor the Durable-LLM API to fit your specific enterprise needs.
|
27
|
+
- **Advanced Webhooks**: Set up complex event-driven workflows with our advanced webhook system.
|
28
|
+
|
29
|
+
## Compliance and Governance
|
30
|
+
|
31
|
+
- **Data Residency Options**: Choose where your data is processed and stored to comply with regional regulations.
|
32
|
+
- **Policy Management**: Implement and enforce organization-wide policies for LLM usage and data handling.
|
33
|
+
|
34
|
+
## Cost Management and Optimization
|
35
|
+
|
36
|
+
- **Usage Analytics**: Detailed breakdowns of API usage and costs across different providers and models.
|
37
|
+
- **Smart Routing**: Automatically route requests to the most cost-effective provider based on your defined rules.
|
38
|
+
- **Budget Controls**: Set spending limits and receive alerts to prevent unexpected costs.
|
39
|
+
|
40
|
+
To learn more about our customized enterprise offerings or to schedule a demo, please contact our sales team at enterprise@durableprogramming.com.
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'durable/llm'
|
3
|
+
require 'durable/llm/client'
|
4
|
+
require 'highline'
|
5
|
+
|
6
|
+
module Durable
|
7
|
+
module Llm
|
8
|
+
class CLI < Thor
|
9
|
+
def self.exit_on_failure?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "prompt PROMPT", "Run a prompt"
|
14
|
+
option :model, aliases: "-m", desc: "Specify the model to use"
|
15
|
+
option :system, aliases: "-s", desc: "Set a system prompt"
|
16
|
+
option :continue, aliases: "-c", type: :boolean, desc: "Continue the previous conversation"
|
17
|
+
option :conversation, aliases: "--cid", desc: "Continue a specific conversation by ID"
|
18
|
+
option :no_stream, type: :boolean, desc: "Disable streaming of tokens"
|
19
|
+
option :option, aliases: "-o", type: :hash, desc: "Set model-specific options"
|
20
|
+
|
21
|
+
def prompt(prompt)
|
22
|
+
config = Durable::Llm.configuration
|
23
|
+
model = options[:model] || "gpt-3.5-turbo"
|
24
|
+
provider_class = Durable::Llm::Providers.model_id_to_provider(model)
|
25
|
+
|
26
|
+
if provider_class.nil?
|
27
|
+
raise "no provider found for model '#{model}'"
|
28
|
+
end
|
29
|
+
|
30
|
+
provider_name = provider_class.name.split('::').last.downcase.to_sym
|
31
|
+
client = Durable::Llm::Client.new(provider_name)
|
32
|
+
|
33
|
+
messages = []
|
34
|
+
messages << { role: "system", content: options[:system] } if options[:system]
|
35
|
+
messages << { role: "user", content: prompt }
|
36
|
+
|
37
|
+
params = {
|
38
|
+
model: model,
|
39
|
+
messages: messages
|
40
|
+
}
|
41
|
+
params.merge!(options[:option]) if options[:option]
|
42
|
+
|
43
|
+
if options[:no_stream]
|
44
|
+
response = client.completion(params)
|
45
|
+
puts response.choices.first.to_s
|
46
|
+
else
|
47
|
+
client.stream(params) do |chunk|
|
48
|
+
print chunk.to_s
|
49
|
+
$stdout.flush
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "chat", "Start an interactive chat"
|
55
|
+
option :model, aliases: "-m", desc: "Specify the model to use"
|
56
|
+
option :system, aliases: "-s", desc: "Set a system prompt"
|
57
|
+
option :continue, aliases: "-c", type: :boolean, desc: "Continue the previous conversation"
|
58
|
+
option :conversation, aliases: "--cid", desc: "Continue a specific conversation by ID"
|
59
|
+
option :option, aliases: "-o", type: :hash, desc: "Set model-specific options"
|
60
|
+
def chat
|
61
|
+
config = Durable::Llm.configuration
|
62
|
+
model = options[:model] || "gpt-3.5-turbo"
|
63
|
+
provider_class = Durable::Llm::Providers.model_id_to_provider(model)
|
64
|
+
|
65
|
+
if provider_class.nil? || provider_class.name.nil?
|
66
|
+
raise "no provider found for model '#{model}'"
|
67
|
+
end
|
68
|
+
|
69
|
+
provider_name = provider_class.name.split('::').last.downcase.to_sym
|
70
|
+
client = Durable::Llm::Client.new(provider_name)
|
71
|
+
|
72
|
+
messages = []
|
73
|
+
messages << { role: "system", content: options[:system] } if options[:system]
|
74
|
+
|
75
|
+
cli = HighLine.new
|
76
|
+
|
77
|
+
cli.say("Chatting with #{model}")
|
78
|
+
cli.say("Type 'exit' or 'quit' to exit")
|
79
|
+
cli.say("Type '!multi' to enter multiple lines, then '!end' to finish")
|
80
|
+
|
81
|
+
loop do
|
82
|
+
input = cli.ask("> ")
|
83
|
+
break if ['exit', 'quit'].include?(input.downcase)
|
84
|
+
|
85
|
+
if input == "!multi"
|
86
|
+
input = cli.ask("Enter multiple lines. Type '!end' to finish:") do |q|
|
87
|
+
q.gather = "!end"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
messages << { role: "user", content: input }
|
92
|
+
params = {
|
93
|
+
model: model,
|
94
|
+
messages: messages
|
95
|
+
}
|
96
|
+
params.merge!(options[:option]) if options[:option]
|
97
|
+
|
98
|
+
response = client.completion(params)
|
99
|
+
cli.say(response.choices.first.to_s)
|
100
|
+
messages << { role: "assistant", content: response.choices.first.to_s }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
desc "models", "List available models"
|
105
|
+
option :options, type: :boolean, desc: "Show model options"
|
106
|
+
def models
|
107
|
+
cli = HighLine.new
|
108
|
+
cli.say("Available models:")
|
109
|
+
|
110
|
+
Durable::Llm::Providers.providers.each do |provider_name|
|
111
|
+
provider_class = Durable::Llm::Providers.const_get(provider_name.to_s.capitalize)
|
112
|
+
provider_models = provider_class.new.models
|
113
|
+
|
114
|
+
cli.say("#{provider_name.to_s.capitalize}:")
|
115
|
+
provider_models.each do |model|
|
116
|
+
cli.say(" #{model}")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'zeitwerk'
|
2
|
+
require 'durable/llm/providers'
|
3
|
+
|
4
|
+
module Durable
|
5
|
+
module Llm
|
6
|
+
class Client
|
7
|
+
attr_reader :provider
|
8
|
+
|
9
|
+
def initialize(provider_name, options = {})
|
10
|
+
provider_class = Durable::Llm::Providers.const_get(provider_name.to_s.capitalize)
|
11
|
+
|
12
|
+
@provider = provider_class.new(**options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def completion(params = {})
|
16
|
+
@provider.completion(params)
|
17
|
+
end
|
18
|
+
|
19
|
+
def chat(params = {})
|
20
|
+
@provider.chat(params)
|
21
|
+
end
|
22
|
+
|
23
|
+
def embed(params = {})
|
24
|
+
@provider.embed(params)
|
25
|
+
end
|
26
|
+
|
27
|
+
def stream(params = {}, &block)
|
28
|
+
@provider.stream(params, &block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Durable
|
4
|
+
module Llm
|
5
|
+
class Configuration
|
6
|
+
attr_accessor :default_provider
|
7
|
+
attr_reader :providers
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@providers = {}
|
11
|
+
load_from_env
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_from_datasette
|
16
|
+
|
17
|
+
config_file = File.expand_path('~/.config/io.datasette.llm/keys.json')
|
18
|
+
|
19
|
+
if File.exist?(config_file)
|
20
|
+
config_data = JSON.parse(File.read(config_file))
|
21
|
+
|
22
|
+
Durable::Llm::Providers.providers.each do |provider|
|
23
|
+
|
24
|
+
@providers[provider.to_sym] ||= OpenStruct.new
|
25
|
+
|
26
|
+
if config_data[provider.to_s]
|
27
|
+
@providers[provider.to_sym][:api_key] = config_data[provider.to_s]
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
rescue JSON::ParserError => e
|
34
|
+
puts "Error parsing JSON file: #{e.message}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def load_from_env
|
38
|
+
ENV.each do |key, value|
|
39
|
+
if key.start_with?('DLLM__')
|
40
|
+
parts = key.split('__')
|
41
|
+
provider = parts[1].downcase.to_sym
|
42
|
+
setting = parts[2].downcase.to_sym
|
43
|
+
@providers[provider] ||= OpenStruct.new
|
44
|
+
@providers[provider][setting] = value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def method_missing(method_name, *args, &block)
|
50
|
+
if method_name.to_s.end_with?('=')
|
51
|
+
provider = method_name.to_s.chomp('=').to_sym
|
52
|
+
@providers[provider] = args.first
|
53
|
+
else
|
54
|
+
@providers[method_name]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def respond_to_missing?(method_name, include_private = false)
|
59
|
+
method_name.to_s.end_with?('=') || @providers.key?(method_name) || super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Durable
|
2
|
+
module Llm
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
class APIError < Error; end
|
6
|
+
|
7
|
+
class RateLimitError < Error; end
|
8
|
+
|
9
|
+
class AuthenticationError < Error; end
|
10
|
+
|
11
|
+
class InvalidRequestError < Error; end
|
12
|
+
|
13
|
+
class ResourceNotFoundError < Error; end
|
14
|
+
|
15
|
+
class TimeoutError < Error; end
|
16
|
+
|
17
|
+
class ServerError < Error; end
|
18
|
+
|
19
|
+
class UnsupportedProviderError < Error; end
|
20
|
+
|
21
|
+
class ConfigurationError < Error; end
|
22
|
+
|
23
|
+
class ModelNotFoundError < Error; end
|
24
|
+
|
25
|
+
class InsufficientQuotaError < Error; end
|
26
|
+
|
27
|
+
class InvalidResponseError < Error; end
|
28
|
+
|
29
|
+
class NetworkError < Error; end
|
30
|
+
|
31
|
+
class StreamingError < Error; end
|
32
|
+
end
|
33
|
+
end
|