htm 0.0.1
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/.architecture/decisions/adrs/001-use-postgresql-timescaledb-storage.md +227 -0
- data/.architecture/decisions/adrs/002-two-tier-memory-architecture.md +322 -0
- data/.architecture/decisions/adrs/003-ollama-default-embedding-provider.md +339 -0
- data/.architecture/decisions/adrs/004-multi-robot-shared-memory-hive-mind.md +374 -0
- data/.architecture/decisions/adrs/005-rag-based-retrieval-with-hybrid-search.md +443 -0
- data/.architecture/decisions/adrs/006-context-assembly-strategies.md +444 -0
- data/.architecture/decisions/adrs/007-working-memory-eviction-strategy.md +461 -0
- data/.architecture/decisions/adrs/008-robot-identification-system.md +550 -0
- data/.architecture/decisions/adrs/009-never-forget-explicit-deletion-only.md +570 -0
- data/.architecture/decisions/adrs/010-redis-working-memory-rejected.md +323 -0
- data/.architecture/decisions/adrs/011-database-side-embedding-generation-with-pgai.md +585 -0
- data/.architecture/decisions/adrs/012-llm-driven-ontology-topic-extraction.md +583 -0
- data/.architecture/decisions/adrs/013-activerecord-orm-and-many-to-many-tagging.md +299 -0
- data/.architecture/decisions/adrs/014-client-side-embedding-generation-workflow.md +569 -0
- data/.architecture/decisions/adrs/015-hierarchical-tag-ontology-and-llm-extraction.md +701 -0
- data/.architecture/decisions/adrs/016-async-embedding-and-tag-generation.md +694 -0
- data/.architecture/members.yml +144 -0
- data/.architecture/reviews/2025-10-29-llm-configuration-and-async-processing-review.md +1137 -0
- data/.architecture/reviews/initial-system-analysis.md +330 -0
- data/.envrc +32 -0
- data/.irbrc +145 -0
- data/CHANGELOG.md +150 -0
- data/COMMITS.md +196 -0
- data/LICENSE +21 -0
- data/README.md +1347 -0
- data/Rakefile +51 -0
- data/SETUP.md +268 -0
- data/config/database.yml +67 -0
- data/db/migrate/20250101000001_enable_extensions.rb +14 -0
- data/db/migrate/20250101000002_create_robots.rb +14 -0
- data/db/migrate/20250101000003_create_nodes.rb +42 -0
- data/db/migrate/20250101000005_create_tags.rb +38 -0
- data/db/migrate/20250101000007_add_node_vector_indexes.rb +30 -0
- data/db/schema.sql +473 -0
- data/db/seed_data/README.md +100 -0
- data/db/seed_data/presidents.md +136 -0
- data/db/seed_data/states.md +151 -0
- data/db/seeds.rb +208 -0
- data/dbdoc/README.md +173 -0
- data/dbdoc/public.node_stats.md +48 -0
- data/dbdoc/public.node_stats.svg +41 -0
- data/dbdoc/public.node_tags.md +40 -0
- data/dbdoc/public.node_tags.svg +112 -0
- data/dbdoc/public.nodes.md +54 -0
- data/dbdoc/public.nodes.svg +118 -0
- data/dbdoc/public.nodes_tags.md +39 -0
- data/dbdoc/public.nodes_tags.svg +112 -0
- data/dbdoc/public.ontology_structure.md +48 -0
- data/dbdoc/public.ontology_structure.svg +38 -0
- data/dbdoc/public.operations_log.md +42 -0
- data/dbdoc/public.operations_log.svg +130 -0
- data/dbdoc/public.relationships.md +39 -0
- data/dbdoc/public.relationships.svg +41 -0
- data/dbdoc/public.robot_activity.md +46 -0
- data/dbdoc/public.robot_activity.svg +35 -0
- data/dbdoc/public.robots.md +35 -0
- data/dbdoc/public.robots.svg +90 -0
- data/dbdoc/public.schema_migrations.md +29 -0
- data/dbdoc/public.schema_migrations.svg +26 -0
- data/dbdoc/public.tags.md +35 -0
- data/dbdoc/public.tags.svg +60 -0
- data/dbdoc/public.topic_relationships.md +45 -0
- data/dbdoc/public.topic_relationships.svg +32 -0
- data/dbdoc/schema.json +1437 -0
- data/dbdoc/schema.svg +154 -0
- data/docs/api/database.md +806 -0
- data/docs/api/embedding-service.md +532 -0
- data/docs/api/htm.md +797 -0
- data/docs/api/index.md +259 -0
- data/docs/api/long-term-memory.md +1096 -0
- data/docs/api/working-memory.md +665 -0
- data/docs/architecture/adrs/001-postgresql-timescaledb.md +314 -0
- data/docs/architecture/adrs/002-two-tier-memory.md +411 -0
- data/docs/architecture/adrs/003-ollama-embeddings.md +421 -0
- data/docs/architecture/adrs/004-hive-mind.md +437 -0
- data/docs/architecture/adrs/005-rag-retrieval.md +531 -0
- data/docs/architecture/adrs/006-context-assembly.md +496 -0
- data/docs/architecture/adrs/007-eviction-strategy.md +645 -0
- data/docs/architecture/adrs/008-robot-identification.md +625 -0
- data/docs/architecture/adrs/009-never-forget.md +648 -0
- data/docs/architecture/adrs/010-redis-working-memory-rejected.md +323 -0
- data/docs/architecture/adrs/011-pgai-integration.md +494 -0
- data/docs/architecture/adrs/index.md +215 -0
- data/docs/architecture/hive-mind.md +736 -0
- data/docs/architecture/index.md +351 -0
- data/docs/architecture/overview.md +538 -0
- data/docs/architecture/two-tier-memory.md +873 -0
- data/docs/assets/css/custom.css +83 -0
- data/docs/assets/images/htm-core-components.svg +63 -0
- data/docs/assets/images/htm-database-schema.svg +93 -0
- data/docs/assets/images/htm-hive-mind-architecture.svg +125 -0
- data/docs/assets/images/htm-importance-scoring-framework.svg +83 -0
- data/docs/assets/images/htm-layered-architecture.svg +71 -0
- data/docs/assets/images/htm-long-term-memory-architecture.svg +115 -0
- data/docs/assets/images/htm-working-memory-architecture.svg +120 -0
- data/docs/assets/images/htm.jpg +0 -0
- data/docs/assets/images/htm_demo.gif +0 -0
- data/docs/assets/js/mathjax.js +18 -0
- data/docs/assets/videos/htm_video.mp4 +0 -0
- data/docs/database_rake_tasks.md +322 -0
- data/docs/development/contributing.md +787 -0
- data/docs/development/index.md +336 -0
- data/docs/development/schema.md +596 -0
- data/docs/development/setup.md +719 -0
- data/docs/development/testing.md +819 -0
- data/docs/guides/adding-memories.md +824 -0
- data/docs/guides/context-assembly.md +1009 -0
- data/docs/guides/getting-started.md +577 -0
- data/docs/guides/index.md +118 -0
- data/docs/guides/long-term-memory.md +941 -0
- data/docs/guides/multi-robot.md +866 -0
- data/docs/guides/recalling-memories.md +927 -0
- data/docs/guides/search-strategies.md +953 -0
- data/docs/guides/working-memory.md +717 -0
- data/docs/index.md +214 -0
- data/docs/installation.md +477 -0
- data/docs/multi_framework_support.md +519 -0
- data/docs/quick-start.md +655 -0
- data/docs/setup_local_database.md +302 -0
- data/docs/using_rake_tasks_in_your_app.md +383 -0
- data/examples/basic_usage.rb +93 -0
- data/examples/cli_app/README.md +317 -0
- data/examples/cli_app/htm_cli.rb +270 -0
- data/examples/custom_llm_configuration.rb +183 -0
- data/examples/example_app/Rakefile +71 -0
- data/examples/example_app/app.rb +206 -0
- data/examples/sinatra_app/Gemfile +21 -0
- data/examples/sinatra_app/app.rb +335 -0
- data/lib/htm/active_record_config.rb +113 -0
- data/lib/htm/configuration.rb +342 -0
- data/lib/htm/database.rb +594 -0
- data/lib/htm/embedding_service.rb +115 -0
- data/lib/htm/errors.rb +34 -0
- data/lib/htm/job_adapter.rb +154 -0
- data/lib/htm/jobs/generate_embedding_job.rb +65 -0
- data/lib/htm/jobs/generate_tags_job.rb +82 -0
- data/lib/htm/long_term_memory.rb +965 -0
- data/lib/htm/models/node.rb +109 -0
- data/lib/htm/models/node_tag.rb +33 -0
- data/lib/htm/models/robot.rb +52 -0
- data/lib/htm/models/tag.rb +76 -0
- data/lib/htm/railtie.rb +76 -0
- data/lib/htm/sinatra.rb +157 -0
- data/lib/htm/tag_service.rb +135 -0
- data/lib/htm/tasks.rb +38 -0
- data/lib/htm/version.rb +5 -0
- data/lib/htm/working_memory.rb +182 -0
- data/lib/htm.rb +400 -0
- data/lib/tasks/db.rake +19 -0
- data/lib/tasks/htm.rake +147 -0
- data/lib/tasks/jobs.rake +312 -0
- data/mkdocs.yml +190 -0
- data/scripts/install_local_database.sh +309 -0
- metadata +341 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'errors'
|
|
4
|
+
require 'logger'
|
|
5
|
+
|
|
6
|
+
class HTM
|
|
7
|
+
# HTM Configuration
|
|
8
|
+
#
|
|
9
|
+
# Applications using HTM should configure LLM access by providing two methods:
|
|
10
|
+
# 1. embedding_generator - Converts text to vector embeddings
|
|
11
|
+
# 2. tag_extractor - Extracts hierarchical tags from text
|
|
12
|
+
# 3. logger - Logger instance for HTM operations
|
|
13
|
+
#
|
|
14
|
+
# @example Configure with custom methods
|
|
15
|
+
# HTM.configure do |config|
|
|
16
|
+
# config.embedding_generator = ->(text) {
|
|
17
|
+
# MyApp::LLMService.embed(text) # Returns Array<Float>
|
|
18
|
+
# }
|
|
19
|
+
# config.tag_extractor = ->(text, ontology) {
|
|
20
|
+
# MyApp::LLMService.extract_tags(text, ontology) # Returns Array<String>
|
|
21
|
+
# }
|
|
22
|
+
# config.logger = Rails.logger # Use Rails logger
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# @example Use defaults with custom timeouts
|
|
26
|
+
# HTM.configure do |config|
|
|
27
|
+
# config.embedding_timeout = 60 # 1 minute for faster models
|
|
28
|
+
# config.tag_timeout = 300 # 5 minutes for larger models
|
|
29
|
+
# config.connection_timeout = 10 # 10 seconds connection timeout
|
|
30
|
+
# config.reset_to_defaults # Apply default implementations with new timeouts
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# @example Use defaults
|
|
34
|
+
# HTM.configure # Uses default implementations
|
|
35
|
+
#
|
|
36
|
+
class Configuration
|
|
37
|
+
attr_accessor :embedding_generator, :tag_extractor, :token_counter
|
|
38
|
+
attr_accessor :embedding_model, :embedding_provider, :embedding_dimensions
|
|
39
|
+
attr_accessor :tag_model, :tag_provider
|
|
40
|
+
attr_accessor :ollama_url
|
|
41
|
+
attr_accessor :embedding_timeout, :tag_timeout, :connection_timeout
|
|
42
|
+
attr_accessor :logger
|
|
43
|
+
attr_accessor :job_backend
|
|
44
|
+
|
|
45
|
+
def initialize
|
|
46
|
+
# Default configuration
|
|
47
|
+
@embedding_provider = :ollama
|
|
48
|
+
@embedding_model = 'nomic-embed-text'
|
|
49
|
+
@embedding_dimensions = 768
|
|
50
|
+
|
|
51
|
+
@tag_provider = :ollama
|
|
52
|
+
@tag_model = 'llama3'
|
|
53
|
+
|
|
54
|
+
@ollama_url = ENV['OLLAMA_URL'] || 'http://localhost:11434'
|
|
55
|
+
|
|
56
|
+
# Timeout settings (in seconds) - apply to all LLM providers
|
|
57
|
+
@embedding_timeout = 120 # 2 minutes for embedding generation
|
|
58
|
+
@tag_timeout = 180 # 3 minutes for tag generation (LLM inference)
|
|
59
|
+
@connection_timeout = 30 # 30 seconds for initial connection
|
|
60
|
+
|
|
61
|
+
# Default logger (STDOUT with INFO level)
|
|
62
|
+
@logger = default_logger
|
|
63
|
+
|
|
64
|
+
# Auto-detect job backend based on environment
|
|
65
|
+
@job_backend = detect_job_backend
|
|
66
|
+
|
|
67
|
+
# Set default implementations
|
|
68
|
+
reset_to_defaults
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Reset to default RubyLLM-based implementations
|
|
72
|
+
def reset_to_defaults
|
|
73
|
+
@embedding_generator = default_embedding_generator
|
|
74
|
+
@tag_extractor = default_tag_extractor
|
|
75
|
+
@token_counter = default_token_counter
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Validate configuration
|
|
79
|
+
def validate!
|
|
80
|
+
unless @embedding_generator.respond_to?(:call)
|
|
81
|
+
raise HTM::ValidationError, "embedding_generator must be callable (proc, lambda, or object responding to :call)"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
unless @tag_extractor.respond_to?(:call)
|
|
85
|
+
raise HTM::ValidationError, "tag_extractor must be callable (proc, lambda, or object responding to :call)"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
unless @token_counter.respond_to?(:call)
|
|
89
|
+
raise HTM::ValidationError, "token_counter must be callable (proc, lambda, or object responding to :call)"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
unless @logger.respond_to?(:info) && @logger.respond_to?(:warn) && @logger.respond_to?(:error)
|
|
93
|
+
raise HTM::ValidationError, "logger must respond to :info, :warn, and :error"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
unless [:active_job, :sidekiq, :inline, :thread].include?(@job_backend)
|
|
97
|
+
raise HTM::ValidationError, "job_backend must be one of: :active_job, :sidekiq, :inline, :thread (got #{@job_backend.inspect})"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
# Auto-detect appropriate job backend based on environment
|
|
104
|
+
#
|
|
105
|
+
# Detection priority:
|
|
106
|
+
# 1. ActiveJob (if defined) - Rails applications
|
|
107
|
+
# 2. Sidekiq (if defined) - Sinatra and other web apps
|
|
108
|
+
# 3. Inline (if test environment) - Test suites
|
|
109
|
+
# 4. Thread (default fallback) - CLI and standalone apps
|
|
110
|
+
#
|
|
111
|
+
# @return [Symbol] Detected job backend
|
|
112
|
+
#
|
|
113
|
+
def detect_job_backend
|
|
114
|
+
# Check for explicit environment variable override
|
|
115
|
+
if ENV['HTM_JOB_BACKEND']
|
|
116
|
+
return ENV['HTM_JOB_BACKEND'].to_sym
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Detect test environment - use inline for synchronous execution
|
|
120
|
+
test_env = ENV['RACK_ENV'] == 'test' || ENV['RAILS_ENV'] == 'test' || ENV['APP_ENV'] == 'test'
|
|
121
|
+
return :inline if test_env
|
|
122
|
+
|
|
123
|
+
# Detect Rails - prefer ActiveJob
|
|
124
|
+
if defined?(ActiveJob)
|
|
125
|
+
return :active_job
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Detect Sidekiq - direct integration for Sinatra apps
|
|
129
|
+
if defined?(Sidekiq)
|
|
130
|
+
return :sidekiq
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Default fallback - simple threading for standalone/CLI apps
|
|
134
|
+
:thread
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Default logger configuration
|
|
138
|
+
def default_logger
|
|
139
|
+
logger = Logger.new($stdout)
|
|
140
|
+
logger.level = ENV.fetch('HTM_LOG_LEVEL', 'INFO').upcase.to_sym
|
|
141
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
|
142
|
+
"[#{datetime.strftime('%Y-%m-%d %H:%M:%S')}] #{severity} -- HTM: #{msg}\n"
|
|
143
|
+
end
|
|
144
|
+
logger
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Default token counter using Tiktoken
|
|
148
|
+
def default_token_counter
|
|
149
|
+
lambda do |text|
|
|
150
|
+
require 'tiktoken_ruby' unless defined?(Tiktoken)
|
|
151
|
+
encoder = Tiktoken.encoding_for_model("gpt-3.5-turbo")
|
|
152
|
+
encoder.encode(text).length
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Default embedding generator using Ollama HTTP API
|
|
157
|
+
#
|
|
158
|
+
# @return [Proc] Callable that takes text and returns embedding vector
|
|
159
|
+
#
|
|
160
|
+
def default_embedding_generator
|
|
161
|
+
lambda do |text|
|
|
162
|
+
require 'net/http'
|
|
163
|
+
require 'json'
|
|
164
|
+
|
|
165
|
+
case @embedding_provider
|
|
166
|
+
when :ollama
|
|
167
|
+
uri = URI("#{@ollama_url}/api/embeddings")
|
|
168
|
+
request = Net::HTTP::Post.new(uri)
|
|
169
|
+
request['Content-Type'] = 'application/json'
|
|
170
|
+
request.body = { model: @embedding_model, prompt: text }.to_json
|
|
171
|
+
|
|
172
|
+
response = Net::HTTP.start(uri.hostname, uri.port,
|
|
173
|
+
read_timeout: @embedding_timeout,
|
|
174
|
+
open_timeout: @connection_timeout) do |http|
|
|
175
|
+
http.request(request)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
data = JSON.parse(response.body)
|
|
179
|
+
embedding = data['embedding']
|
|
180
|
+
|
|
181
|
+
unless embedding.is_a?(Array)
|
|
182
|
+
raise HTM::EmbeddingError, "Invalid embedding response format"
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
embedding
|
|
186
|
+
else
|
|
187
|
+
raise HTM::EmbeddingError, "Unsupported embedding provider: #{@embedding_provider}. Only :ollama is currently supported."
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Default tag extractor using Ollama HTTP API
|
|
193
|
+
#
|
|
194
|
+
# @return [Proc] Callable that takes text and ontology, returns array of tags
|
|
195
|
+
#
|
|
196
|
+
def default_tag_extractor
|
|
197
|
+
lambda do |text, existing_ontology = []|
|
|
198
|
+
require 'net/http'
|
|
199
|
+
require 'json'
|
|
200
|
+
|
|
201
|
+
# Build prompt
|
|
202
|
+
ontology_context = if existing_ontology.any?
|
|
203
|
+
sample_tags = existing_ontology.sample([existing_ontology.size, 20].min)
|
|
204
|
+
"Existing ontology includes: #{sample_tags.join(', ')}\n"
|
|
205
|
+
else
|
|
206
|
+
"This is a new ontology - create appropriate hierarchical tags.\n"
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
prompt = <<~PROMPT
|
|
210
|
+
Extract hierarchical topic tags from the following text.
|
|
211
|
+
|
|
212
|
+
#{ontology_context}
|
|
213
|
+
Format: root:level1:level2:level3 (use colons to separate levels)
|
|
214
|
+
|
|
215
|
+
Rules:
|
|
216
|
+
- Use lowercase letters, numbers, and hyphens only
|
|
217
|
+
- Maximum depth: 5 levels
|
|
218
|
+
- Return 2-5 tags per text
|
|
219
|
+
- Tags should be reusable and consistent
|
|
220
|
+
- Prefer existing ontology tags when applicable
|
|
221
|
+
- Use hyphens for multi-word terms (e.g., natural-language-processing)
|
|
222
|
+
|
|
223
|
+
Text: #{text}
|
|
224
|
+
|
|
225
|
+
Return ONLY the topic tags, one per line, no explanations.
|
|
226
|
+
PROMPT
|
|
227
|
+
|
|
228
|
+
case @tag_provider
|
|
229
|
+
when :ollama
|
|
230
|
+
uri = URI("#{@ollama_url}/api/generate")
|
|
231
|
+
request = Net::HTTP::Post.new(uri)
|
|
232
|
+
request['Content-Type'] = 'application/json'
|
|
233
|
+
request.body = {
|
|
234
|
+
model: @tag_model,
|
|
235
|
+
prompt: prompt,
|
|
236
|
+
system: 'You are a precise topic extraction system. Output only topic tags in hierarchical format: root:subtopic:detail',
|
|
237
|
+
stream: false,
|
|
238
|
+
options: { temperature: 0 }
|
|
239
|
+
}.to_json
|
|
240
|
+
|
|
241
|
+
response = Net::HTTP.start(uri.hostname, uri.port,
|
|
242
|
+
read_timeout: @tag_timeout,
|
|
243
|
+
open_timeout: @connection_timeout) do |http|
|
|
244
|
+
http.request(request)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
data = JSON.parse(response.body)
|
|
248
|
+
response_text = data['response']
|
|
249
|
+
|
|
250
|
+
# Parse and validate tags
|
|
251
|
+
tags = response_text.to_s.split("\n").map(&:strip).reject(&:empty?)
|
|
252
|
+
|
|
253
|
+
# Validate format: lowercase alphanumeric + hyphens + colons
|
|
254
|
+
valid_tags = tags.select do |tag|
|
|
255
|
+
tag =~ /^[a-z0-9\-]+(:[a-z0-9\-]+)*$/
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Limit depth to 5 levels (4 colons maximum)
|
|
259
|
+
valid_tags.select { |tag| tag.count(':') < 5 }
|
|
260
|
+
else
|
|
261
|
+
raise HTM::TagError, "Unsupported tag provider: #{@tag_provider}. Only :ollama is currently supported."
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
class << self
|
|
268
|
+
attr_writer :configuration
|
|
269
|
+
|
|
270
|
+
# Get current configuration
|
|
271
|
+
#
|
|
272
|
+
# @return [HTM::Configuration]
|
|
273
|
+
#
|
|
274
|
+
def configuration
|
|
275
|
+
@configuration ||= Configuration.new
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Configure HTM
|
|
279
|
+
#
|
|
280
|
+
# @yield [config] Configuration object
|
|
281
|
+
# @yieldparam config [HTM::Configuration]
|
|
282
|
+
#
|
|
283
|
+
# @example Custom configuration
|
|
284
|
+
# HTM.configure do |config|
|
|
285
|
+
# config.embedding_generator = ->(text) { MyEmbedder.embed(text) }
|
|
286
|
+
# config.tag_extractor = ->(text, ontology) { MyTagger.extract(text, ontology) }
|
|
287
|
+
# end
|
|
288
|
+
#
|
|
289
|
+
# @example Default configuration
|
|
290
|
+
# HTM.configure # Uses RubyLLM defaults
|
|
291
|
+
#
|
|
292
|
+
def configure
|
|
293
|
+
yield(configuration) if block_given?
|
|
294
|
+
configuration.validate!
|
|
295
|
+
configuration
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Reset configuration to defaults
|
|
299
|
+
def reset_configuration!
|
|
300
|
+
@configuration = Configuration.new
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Generate embedding using EmbeddingService
|
|
304
|
+
#
|
|
305
|
+
# @param text [String] Text to embed
|
|
306
|
+
# @return [Array<Float>] Embedding vector (original, not padded)
|
|
307
|
+
#
|
|
308
|
+
def embed(text)
|
|
309
|
+
result = HTM::EmbeddingService.generate(text)
|
|
310
|
+
result[:embedding]
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# Extract tags using TagService
|
|
314
|
+
#
|
|
315
|
+
# @param text [String] Text to analyze
|
|
316
|
+
# @param existing_ontology [Array<String>] Sample of existing tags for context
|
|
317
|
+
# @return [Array<String>] Extracted and validated tag names
|
|
318
|
+
#
|
|
319
|
+
def extract_tags(text, existing_ontology: [])
|
|
320
|
+
HTM::TagService.extract(text, existing_ontology: existing_ontology)
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# Count tokens using configured counter
|
|
324
|
+
#
|
|
325
|
+
# @param text [String] Text to count tokens for
|
|
326
|
+
# @return [Integer] Token count
|
|
327
|
+
#
|
|
328
|
+
def count_tokens(text)
|
|
329
|
+
configuration.token_counter.call(text)
|
|
330
|
+
rescue StandardError => e
|
|
331
|
+
raise HTM::ValidationError, "Token counting failed: #{e.message}"
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Get configured logger
|
|
335
|
+
#
|
|
336
|
+
# @return [Logger] Configured logger instance
|
|
337
|
+
#
|
|
338
|
+
def logger
|
|
339
|
+
configuration.logger
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
end
|