red-candle 1.2.2 → 1.2.3
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/Cargo.lock +2 -2
- data/LICENSE +1 -1
- data/README.md +7 -7
- data/lib/candle/build_info.rb +6 -7
- data/lib/candle/device_utils.rb +1 -1
- data/lib/candle/llm.rb +2 -2
- data/lib/candle/logger.rb +149 -0
- data/lib/candle/ner.rb +1 -1
- data/lib/candle/version.rb +1 -1
- data/lib/candle.rb +1 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d5cfca9bb05ab3dd9e8b1f1d92db4d94190b9acf473a41c7eb8a35c51a1a94a
|
4
|
+
data.tar.gz: aa2028e08fde8be4d9fd55b9719beab8ee8afabdc240900f176d88f7888bae6f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16426f08f0cf7fd5ec1353adb139702c662df714a9d6fa7c3ed4d8feac81ba0313dcb58874c13b76c47ef6d8ca6acf6e22c8818888bf1affbcbc3d3b3a6fde96
|
7
|
+
data.tar.gz: 82f161767e7214ed97f36127d979da634507584f3c8110aa4672876d78edd6c9af0494f473e1a22f83311f7ebdf7e7ab8c41ec6451e5cf433b6a5acdc2ea603f
|
data/Cargo.lock
CHANGED
@@ -2999,9 +2999,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|
2999
2999
|
|
3000
3000
|
[[package]]
|
3001
3001
|
name = "slab"
|
3002
|
-
version = "0.4.
|
3002
|
+
version = "0.4.11"
|
3003
3003
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
3004
|
-
checksum = "
|
3004
|
+
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
|
3005
3005
|
|
3006
3006
|
[[package]]
|
3007
3007
|
name = "smallvec"
|
data/LICENSE
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
MIT License
|
2
2
|
|
3
3
|
Copyright (c) 2023 kojix2
|
4
|
-
Copyright (c) 2024 Christopher Petersen
|
4
|
+
Copyright (c) 2024, 2025 Christopher Petersen
|
5
5
|
|
6
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
7
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
<img src="/docs/assets/logo-title.png" alt="red-candle" height="80px">
|
2
2
|
|
3
|
-
[](https://github.com/scientist-labs/red-candle/actions/workflows/build.yml)
|
4
4
|
[](https://badge.fury.io/rb/red-candle)
|
5
5
|
|
6
6
|
Run state-of-the-art **language models directly from Ruby**. No Python, no APIs, no external services - just Ruby with blazing-fast Rust under the hood. Hardware accelerated with **Metal (Mac)** and **CUDA (NVIDIA).** Red candle leverages the Rust ecosystem, notably [Candle](https://github.com/huggingface/candle) and [Magnus](https://github.com/matsadler/magnus), to provide a fast and efficient way to run LLMs in Ruby. See [Dependencies](#dependencies) for more.
|
@@ -509,7 +509,7 @@ Choose based on your needs:
|
|
509
509
|
```ruby
|
510
510
|
# Good: Single call with multiple documents
|
511
511
|
results = reranker.rerank(query, documents)
|
512
|
-
|
512
|
+
|
513
513
|
# Less efficient: Multiple calls
|
514
514
|
documents.map { |doc| reranker.rerank(query, [doc]) }
|
515
515
|
```
|
@@ -525,21 +525,21 @@ Choose based on your needs:
|
|
525
525
|
# Split into overlapping chunks
|
526
526
|
words = long_text.split
|
527
527
|
chunks = []
|
528
|
-
|
528
|
+
|
529
529
|
(0...words.length).step(chunk_size - 50) do |i|
|
530
530
|
chunk = words[i...(i + chunk_size)].join(" ")
|
531
531
|
chunks << chunk
|
532
532
|
end
|
533
|
-
|
533
|
+
|
534
534
|
# Rerank chunks
|
535
535
|
results = reranker.rerank(query, chunks)
|
536
|
-
|
536
|
+
|
537
537
|
# Return best chunk
|
538
538
|
results.max_by { |r| r[:score] }
|
539
539
|
end
|
540
540
|
```
|
541
541
|
|
542
|
-
5. **Memory Usage**:
|
542
|
+
5. **Memory Usage**:
|
543
543
|
- Model size: ~125MB
|
544
544
|
- Each batch processes all documents simultaneously
|
545
545
|
- Consider batching if you have many documents
|
@@ -949,7 +949,7 @@ Failed to load GGUF model: cannot find llama.attention.head_count in metadata (R
|
|
949
949
|
FORK IT!
|
950
950
|
|
951
951
|
```
|
952
|
-
git clone https://github.com/
|
952
|
+
git clone https://github.com/scientist-labs/red-candle
|
953
953
|
cd red-candle
|
954
954
|
bundle
|
955
955
|
bundle exec rake compile
|
data/lib/candle/build_info.rb
CHANGED
@@ -3,8 +3,7 @@ module Candle
|
|
3
3
|
def self.display_cuda_info
|
4
4
|
info = Candle.build_info
|
5
5
|
|
6
|
-
#
|
7
|
-
return unless ENV['CANDLE_VERBOSE'] || ENV['CANDLE_DEBUG'] || $DEBUG
|
6
|
+
# CUDA info is now controlled by logger level
|
8
7
|
|
9
8
|
if info["cuda_available"] == false
|
10
9
|
# :nocov:
|
@@ -13,11 +12,11 @@ module Candle
|
|
13
12
|
File.exist?('/usr/local/cuda') || File.exist?('/opt/cuda')
|
14
13
|
|
15
14
|
if cuda_potentially_available
|
16
|
-
warn "=" * 80
|
17
|
-
warn "Red Candle: CUDA detected on system but not enabled in build."
|
18
|
-
warn "This may be due to CANDLE_DISABLE_CUDA being set during installation."
|
19
|
-
warn "To enable CUDA support, reinstall without CANDLE_DISABLE_CUDA set."
|
20
|
-
warn "=" * 80
|
15
|
+
Candle.logger.warn "=" * 80
|
16
|
+
Candle.logger.warn "Red Candle: CUDA detected on system but not enabled in build."
|
17
|
+
Candle.logger.warn "This may be due to CANDLE_DISABLE_CUDA being set during installation."
|
18
|
+
Candle.logger.warn "To enable CUDA support, reinstall without CANDLE_DISABLE_CUDA set."
|
19
|
+
Candle.logger.warn "=" * 80
|
21
20
|
end
|
22
21
|
# :nocov:
|
23
22
|
end
|
data/lib/candle/device_utils.rb
CHANGED
@@ -3,7 +3,7 @@ module Candle
|
|
3
3
|
# @deprecated Use {Candle::Device.best} instead
|
4
4
|
# Get the best available device (Metal > CUDA > CPU)
|
5
5
|
def self.best_device
|
6
|
-
warn "[DEPRECATION] `DeviceUtils.best_device` is deprecated. Please use `Device.best` instead."
|
6
|
+
Candle.logger.warn "[DEPRECATION] `DeviceUtils.best_device` is deprecated. Please use `Device.best` instead."
|
7
7
|
Device.best
|
8
8
|
end
|
9
9
|
end
|
data/lib/candle/llm.rb
CHANGED
@@ -78,7 +78,7 @@ module Candle
|
|
78
78
|
JSON.parse(json_content)
|
79
79
|
rescue JSON::ParserError => e
|
80
80
|
# Return the raw string if parsing fails
|
81
|
-
warn "
|
81
|
+
Candle.logger.warn "Generated output is not valid JSON: #{e.message}" if options[:warn_on_parse_error]
|
82
82
|
result
|
83
83
|
end
|
84
84
|
end
|
@@ -261,7 +261,7 @@ module Candle
|
|
261
261
|
if e.message.include?("No tokenizer found")
|
262
262
|
# Auto-detect tokenizer
|
263
263
|
detected_tokenizer = guess_tokenizer(model_id)
|
264
|
-
|
264
|
+
Candle.logger.info "No tokenizer found in GGUF repo. Using tokenizer from: #{detected_tokenizer}"
|
265
265
|
model_str = "#{model_str}@@#{detected_tokenizer}"
|
266
266
|
_from_pretrained(model_str, device)
|
267
267
|
else
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Candle
|
4
|
+
# Logging functionality for the Red Candle gem
|
5
|
+
class << self
|
6
|
+
# Get the current logger instance
|
7
|
+
# @return [Logger] The logger instance
|
8
|
+
def logger
|
9
|
+
@logger ||= create_default_logger
|
10
|
+
end
|
11
|
+
|
12
|
+
# Set a custom logger instance
|
13
|
+
# @param custom_logger [Logger] A custom logger instance
|
14
|
+
def logger=(custom_logger)
|
15
|
+
@logger = custom_logger
|
16
|
+
end
|
17
|
+
|
18
|
+
# Configure logging with a block
|
19
|
+
# @yield [config] Configuration object
|
20
|
+
def configure_logging
|
21
|
+
config = LoggerConfig.new
|
22
|
+
yield config if block_given?
|
23
|
+
@logger = config.build_logger
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Create the default logger with CLI-friendly settings
|
29
|
+
# @return [Logger] Configured logger instance
|
30
|
+
def create_default_logger
|
31
|
+
logger = Logger.new($stderr)
|
32
|
+
logger.level = default_log_level
|
33
|
+
logger.formatter = cli_friendly_formatter
|
34
|
+
logger
|
35
|
+
end
|
36
|
+
|
37
|
+
# Determine default log level based on environment variables
|
38
|
+
# @return [Integer] Logger level constant
|
39
|
+
def default_log_level
|
40
|
+
# Support legacy CANDLE_VERBOSE for backward compatibility, but prefer explicit configuration
|
41
|
+
return Logger::DEBUG if ENV['CANDLE_VERBOSE']
|
42
|
+
Logger::WARN # CLI-friendly: only show warnings/errors by default
|
43
|
+
end
|
44
|
+
|
45
|
+
# CLI-friendly formatter that outputs just the message
|
46
|
+
# @return [Proc] Formatter proc
|
47
|
+
def cli_friendly_formatter
|
48
|
+
proc { |severity, datetime, progname, msg| "#{msg}\n" }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Configuration helper for logger setup
|
53
|
+
class LoggerConfig
|
54
|
+
attr_accessor :level, :output, :formatter
|
55
|
+
|
56
|
+
def initialize
|
57
|
+
@level = :warn
|
58
|
+
@output = $stderr
|
59
|
+
@formatter = :simple
|
60
|
+
end
|
61
|
+
|
62
|
+
# Build a logger from the configuration
|
63
|
+
# @return [Logger] Configured logger
|
64
|
+
def build_logger
|
65
|
+
logger = Logger.new(@output)
|
66
|
+
logger.level = normalize_level(@level)
|
67
|
+
logger.formatter = build_formatter(@formatter)
|
68
|
+
logger
|
69
|
+
end
|
70
|
+
|
71
|
+
# Set log level to debug (verbose output)
|
72
|
+
def verbose!
|
73
|
+
@level = :debug
|
74
|
+
end
|
75
|
+
|
76
|
+
# Set log level to info
|
77
|
+
def info!
|
78
|
+
@level = :info
|
79
|
+
end
|
80
|
+
|
81
|
+
# Set log level to warn (default)
|
82
|
+
def quiet!
|
83
|
+
@level = :warn
|
84
|
+
end
|
85
|
+
|
86
|
+
# Set log level to error (minimal output)
|
87
|
+
def silent!
|
88
|
+
@level = :error
|
89
|
+
end
|
90
|
+
|
91
|
+
# Log to stdout instead of stderr
|
92
|
+
def log_to_stdout!
|
93
|
+
@output = $stdout
|
94
|
+
end
|
95
|
+
|
96
|
+
# Log to a file
|
97
|
+
# @param file_path [String] Path to log file
|
98
|
+
def log_to_file!(file_path)
|
99
|
+
@output = file_path
|
100
|
+
end
|
101
|
+
|
102
|
+
# Disable logging completely
|
103
|
+
def disable!
|
104
|
+
@output = File::NULL
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
# Convert symbol/string level to Logger constant
|
110
|
+
# @param level [Symbol, String, Integer] Log level
|
111
|
+
# @return [Integer] Logger level constant
|
112
|
+
def normalize_level(level)
|
113
|
+
case level.to_s.downcase
|
114
|
+
when 'debug' then Logger::DEBUG
|
115
|
+
when 'info' then Logger::INFO
|
116
|
+
when 'warn', 'warning' then Logger::WARN
|
117
|
+
when 'error' then Logger::ERROR
|
118
|
+
when 'fatal' then Logger::FATAL
|
119
|
+
else Logger::WARN
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Build formatter based on type
|
124
|
+
# @param formatter_type [Symbol] Type of formatter
|
125
|
+
# @return [Proc] Formatter proc
|
126
|
+
def build_formatter(formatter_type)
|
127
|
+
case formatter_type
|
128
|
+
when :simple, :cli
|
129
|
+
proc { |severity, datetime, progname, msg| "#{msg}\n" }
|
130
|
+
when :detailed
|
131
|
+
proc do |severity, datetime, progname, msg|
|
132
|
+
"[#{datetime.strftime('%Y-%m-%d %H:%M:%S')}] #{severity}: #{msg}\n"
|
133
|
+
end
|
134
|
+
when :json
|
135
|
+
require 'json'
|
136
|
+
proc do |severity, datetime, progname, msg|
|
137
|
+
JSON.generate({
|
138
|
+
timestamp: datetime.iso8601,
|
139
|
+
level: severity,
|
140
|
+
message: msg,
|
141
|
+
program: progname
|
142
|
+
}) + "\n"
|
143
|
+
end
|
144
|
+
else
|
145
|
+
proc { |severity, datetime, progname, msg| "#{msg}\n" }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
data/lib/candle/ner.rb
CHANGED
@@ -196,7 +196,7 @@ module Candle
|
|
196
196
|
# This is especially important for Ruby < 3.2
|
197
197
|
max_length = 1_000_000 # 1MB of text
|
198
198
|
if text.length > max_length
|
199
|
-
warn "PatternEntityRecognizer: Text truncated from #{text.length} to #{max_length} chars for safety"
|
199
|
+
Candle.logger.warn "PatternEntityRecognizer: Text truncated from #{text.length} to #{max_length} chars for safety"
|
200
200
|
text = text[0...max_length]
|
201
201
|
end
|
202
202
|
|
data/lib/candle/version.rb
CHANGED
data/lib/candle.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: red-candle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Petersen
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2025-
|
12
|
+
date: 2025-09-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rb_sys
|
@@ -218,13 +218,14 @@ files:
|
|
218
218
|
- lib/candle/embedding_model.rb
|
219
219
|
- lib/candle/embedding_model_type.rb
|
220
220
|
- lib/candle/llm.rb
|
221
|
+
- lib/candle/logger.rb
|
221
222
|
- lib/candle/ner.rb
|
222
223
|
- lib/candle/reranker.rb
|
223
224
|
- lib/candle/tensor.rb
|
224
225
|
- lib/candle/tokenizer.rb
|
225
226
|
- lib/candle/version.rb
|
226
227
|
- lib/red-candle.rb
|
227
|
-
homepage: https://github.com/
|
228
|
+
homepage: https://github.com/scientist-labs/red-candle
|
228
229
|
licenses:
|
229
230
|
- MIT
|
230
231
|
metadata: {}
|