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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d101e47090a800dddabfa1ee41971ca3f214f9a422e9408c0970b24c03aab8c7
4
- data.tar.gz: 7136f0922548fd4bead034930b3c6d1553c498c23fc17802a6c94f7f4a0c7ce5
3
+ metadata.gz: 2d5cfca9bb05ab3dd9e8b1f1d92db4d94190b9acf473a41c7eb8a35c51a1a94a
4
+ data.tar.gz: aa2028e08fde8be4d9fd55b9719beab8ee8afabdc240900f176d88f7888bae6f
5
5
  SHA512:
6
- metadata.gz: 594900e14d64fc335e53e2599a6e2d81ba4fdb1a1f3d5680536a47538bdf05d12332e959b33b67bfa04cca0dd321835a737d2ddf9cdd33c42b937370dde7a2a1
7
- data.tar.gz: 4005d21ddccce9182d8600af5b3fd3f34ee9fabdf1b8235eb37eb1be7ede74b644c23d4ea322f6c0e05808e3e98e0c2066251111f538e9e8a934e7ec069ae4c0
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.10"
3002
+ version = "0.4.11"
3003
3003
  source = "registry+https://github.com/rust-lang/crates.io-index"
3004
- checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d"
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
- [![build](https://github.com/assaydepot/red-candle/actions/workflows/build.yml/badge.svg)](https://github.com/assaydepot/red-candle/actions/workflows/build.yml)
3
+ [![build](https://github.com/scientist-labs/red-candle/actions/workflows/build.yml/badge.svg)](https://github.com/scientist-labs/red-candle/actions/workflows/build.yml)
4
4
  [![Gem Version](https://badge.fury.io/rb/red-candle.svg)](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/assaydepot/red-candle
952
+ git clone https://github.com/scientist-labs/red-candle
953
953
  cd red-candle
954
954
  bundle
955
955
  bundle exec rake compile
@@ -3,8 +3,7 @@ module Candle
3
3
  def self.display_cuda_info
4
4
  info = Candle.build_info
5
5
 
6
- # Only display CUDA info if running in development or if CANDLE_VERBOSE is set
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
@@ -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 "Warning: Generated output is not valid JSON: #{e.message}" if options[:warn_on_parse_error]
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
- warn "No tokenizer found in GGUF repo. Using tokenizer from: #{detected_tokenizer}"
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
 
@@ -1,5 +1,5 @@
1
1
  # :nocov:
2
2
  module Candle
3
- VERSION = "1.2.2"
3
+ VERSION = "1.2.3"
4
4
  end
5
5
  # :nocov:
data/lib/candle.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require_relative "candle/logger"
1
2
  require_relative "candle/candle"
2
3
  require_relative "candle/tensor"
3
4
  require_relative "candle/device_utils"
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.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-08-13 00:00:00.000000000 Z
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/assaydepot/red-candle
228
+ homepage: https://github.com/scientist-labs/red-candle
228
229
  licenses:
229
230
  - MIT
230
231
  metadata: {}