hokipoki 0.8.5 → 0.8.7
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b5a7fa3a37f4a74900d6a2c6e901ac496e53bc5f393d6af9623e00d7fbdbf2d7
|
|
4
|
+
data.tar.gz: 0c8a79d2d72f2f096d7328b924e68d77c7d4181449f34db9544ded4c388a0fcb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: af5e8f308a673ce3160b5ce0adb627edcebf8c04e7e6574f2cddd7ed70b2010829fdbecec8194865e87a612671aa8b58c406465d2a85711c97fa14e6fba265aa
|
|
7
|
+
data.tar.gz: 39ca391c5e1f001eef3d2dd5052402fe3493ed31c31c4ed8d4d146db9a85b0f0530c0d55a712fa68bcfcfc80a7ec52d40c956149231c337ece1e8bd874d356b4
|
data/bin/gemini_refiner
CHANGED
|
@@ -15,7 +15,7 @@ class GeminiRefiner
|
|
|
15
15
|
@status_file = '/tmp/gemini_status.log'
|
|
16
16
|
@current_refinement_file = '/tmp/gemini_current_refinement.json'
|
|
17
17
|
@batch_size = 10
|
|
18
|
-
@sleep_interval =
|
|
18
|
+
@sleep_interval = 120 # 2 minutes
|
|
19
19
|
@refinement_count = 0
|
|
20
20
|
@start_time = Time.now
|
|
21
21
|
|
|
@@ -67,7 +67,7 @@ class GeminiRefiner
|
|
|
67
67
|
puts "🎯 Configuration:"
|
|
68
68
|
puts " Endpoint: #{@base_url}/api/gemini"
|
|
69
69
|
puts " Batch Size: #{@batch_size} vectors"
|
|
70
|
-
puts " Interval: #{@sleep_interval}
|
|
70
|
+
puts " Interval: #{@sleep_interval / 60} minutes"
|
|
71
71
|
puts " Template: #{@template_file}"
|
|
72
72
|
puts ""
|
|
73
73
|
end
|
|
@@ -129,7 +129,7 @@ class GeminiRefiner
|
|
|
129
129
|
display_current_stats
|
|
130
130
|
end
|
|
131
131
|
else
|
|
132
|
-
puts "💤 No vectors to refine... waiting #{@sleep_interval}
|
|
132
|
+
puts "💤 No vectors to refine... waiting #{@sleep_interval / 60} minutes"
|
|
133
133
|
clear_current_refinement
|
|
134
134
|
end
|
|
135
135
|
|
|
@@ -138,7 +138,7 @@ class GeminiRefiner
|
|
|
138
138
|
rescue => e
|
|
139
139
|
log_status('error', "Refinement loop error: #{e.message}")
|
|
140
140
|
puts "❌ Error in refinement loop: #{e.message}"
|
|
141
|
-
puts " Retrying in #{@sleep_interval}
|
|
141
|
+
puts " Retrying in #{@sleep_interval / 60} minutes..."
|
|
142
142
|
sleep(@sleep_interval)
|
|
143
143
|
end
|
|
144
144
|
end
|
|
@@ -129,11 +129,31 @@ module HiveMind
|
|
|
129
129
|
# Create smart retrieval engine
|
|
130
130
|
template 'smart_retrieval_engine.rb', 'app/services/smart_retrieval_engine.rb'
|
|
131
131
|
say @pastel.green("✓ Created app/services/smart_retrieval_engine.rb")
|
|
132
|
+
|
|
133
|
+
# Create Gemini API controller for vector refinement
|
|
134
|
+
directory 'api', 'app/controllers/api'
|
|
135
|
+
say @pastel.green("✓ Created app/controllers/api/gemini_controller.rb")
|
|
132
136
|
end
|
|
133
137
|
|
|
134
138
|
def setup_routing
|
|
135
|
-
say "\n#{@pastel.cyan('🛣️
|
|
136
|
-
|
|
139
|
+
say "\n#{@pastel.cyan('🛣️ Adding Gemini API routes')}"
|
|
140
|
+
|
|
141
|
+
# Add Gemini API routes
|
|
142
|
+
routes_content = <<~RUBY
|
|
143
|
+
|
|
144
|
+
# Gemini vector refinement API
|
|
145
|
+
namespace :api do
|
|
146
|
+
namespace :gemini do
|
|
147
|
+
get :health_check
|
|
148
|
+
get :unrefined_vectors
|
|
149
|
+
post :submit_refined
|
|
150
|
+
get :stats
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
RUBY
|
|
154
|
+
|
|
155
|
+
append_to_file 'config/routes.rb', routes_content
|
|
156
|
+
say @pastel.green("✓ Added Gemini API routes")
|
|
137
157
|
end
|
|
138
158
|
|
|
139
159
|
def create_cli_tools
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
class Api::GeminiController < ApplicationController
|
|
2
|
+
skip_before_action :verify_authenticity_token
|
|
3
|
+
before_action :log_gemini_activity, except: [:health_check]
|
|
4
|
+
|
|
5
|
+
# Health check endpoint
|
|
6
|
+
def health_check
|
|
7
|
+
render json: {
|
|
8
|
+
status: 'ok',
|
|
9
|
+
timestamp: Time.current,
|
|
10
|
+
system: 'hokipoki_gemini_api'
|
|
11
|
+
}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Endpoint for Gemini to fetch unrefined vectors
|
|
15
|
+
def unrefined_vectors
|
|
16
|
+
begin
|
|
17
|
+
batch_size = params[:batch_size]&.to_i || 10
|
|
18
|
+
batch_size = [batch_size, 50].min # Cap at 50 for safety
|
|
19
|
+
|
|
20
|
+
vectors = HiveMindDocument.where(refined: false)
|
|
21
|
+
.limit(batch_size)
|
|
22
|
+
.order(:created_at)
|
|
23
|
+
|
|
24
|
+
response_data = {
|
|
25
|
+
vectors: vectors.map { |v| format_vector_for_gemini(v) },
|
|
26
|
+
refinement_template: refinement_template,
|
|
27
|
+
batch_info: {
|
|
28
|
+
requested: batch_size,
|
|
29
|
+
returned: vectors.count,
|
|
30
|
+
total_pending: HiveMindDocument.where(refined: false).count
|
|
31
|
+
},
|
|
32
|
+
timestamp: Time.current
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
log_gemini_status('info', "Served #{vectors.count} unrefined vectors to Gemini")
|
|
36
|
+
|
|
37
|
+
render json: response_data
|
|
38
|
+
|
|
39
|
+
rescue => e
|
|
40
|
+
log_gemini_status('error', "Failed to fetch unrefined vectors: #{e.message}")
|
|
41
|
+
|
|
42
|
+
render json: {
|
|
43
|
+
error: 'Failed to fetch vectors',
|
|
44
|
+
message: e.message,
|
|
45
|
+
timestamp: Time.current
|
|
46
|
+
}, status: 500
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Endpoint for Gemini to submit refined vectors
|
|
51
|
+
def submit_refined
|
|
52
|
+
begin
|
|
53
|
+
refined_data = JSON.parse(request.body.read)
|
|
54
|
+
processed_count = 0
|
|
55
|
+
errors = []
|
|
56
|
+
|
|
57
|
+
refined_data['vectors']&.each do |refined|
|
|
58
|
+
begin
|
|
59
|
+
vector = HiveMindDocument.find(refined['id'])
|
|
60
|
+
|
|
61
|
+
# Update with refined data
|
|
62
|
+
update_data = {
|
|
63
|
+
refined: true,
|
|
64
|
+
refined_at: Time.current,
|
|
65
|
+
refined_by: 'gemini'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Add refined content if provided
|
|
69
|
+
if refined['chunks']
|
|
70
|
+
update_data[:chunks] = refined['chunks']
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
if refined['keywords']
|
|
74
|
+
update_data[:keywords] = refined['keywords']
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
if refined['generators']
|
|
78
|
+
update_data[:generators] = refined['generators']
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Store refined metadata
|
|
82
|
+
existing_metadata = vector.metadata || {}
|
|
83
|
+
update_data[:metadata] = existing_metadata.merge({
|
|
84
|
+
'refined_by' => 'gemini',
|
|
85
|
+
'refined_at' => Time.current.iso8601,
|
|
86
|
+
'original_content_length' => vector.content&.length,
|
|
87
|
+
'chunks_count' => refined['chunks']&.length,
|
|
88
|
+
'keywords_count' => refined['keywords']&.length
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
vector.update!(update_data)
|
|
92
|
+
processed_count += 1
|
|
93
|
+
|
|
94
|
+
log_gemini_status('success', "Refined vector ##{vector.id} (#{refined['keywords']&.length || 0} keywords)")
|
|
95
|
+
|
|
96
|
+
rescue => e
|
|
97
|
+
error_msg = "Failed to update vector #{refined['id']}: #{e.message}"
|
|
98
|
+
errors << error_msg
|
|
99
|
+
log_gemini_status('error', error_msg)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
response_data = {
|
|
104
|
+
status: 'success',
|
|
105
|
+
processed: processed_count,
|
|
106
|
+
errors: errors,
|
|
107
|
+
timestamp: Time.current
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if errors.any?
|
|
111
|
+
response_data[:status] = 'partial_success'
|
|
112
|
+
render json: response_data, status: 207 # Multi-status
|
|
113
|
+
else
|
|
114
|
+
render json: response_data
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
rescue JSON::ParserError => e
|
|
118
|
+
log_gemini_status('error', "Invalid JSON in refined data: #{e.message}")
|
|
119
|
+
|
|
120
|
+
render json: {
|
|
121
|
+
error: 'Invalid JSON format',
|
|
122
|
+
message: e.message,
|
|
123
|
+
timestamp: Time.current
|
|
124
|
+
}, status: 400
|
|
125
|
+
|
|
126
|
+
rescue => e
|
|
127
|
+
log_gemini_status('error', "Failed to process refined vectors: #{e.message}")
|
|
128
|
+
|
|
129
|
+
render json: {
|
|
130
|
+
error: 'Failed to process refined vectors',
|
|
131
|
+
message: e.message,
|
|
132
|
+
timestamp: Time.current
|
|
133
|
+
}, status: 500
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Stats endpoint for monitoring
|
|
138
|
+
def stats
|
|
139
|
+
begin
|
|
140
|
+
stats = {
|
|
141
|
+
total_vectors: HiveMindDocument.count,
|
|
142
|
+
refined_vectors: HiveMindDocument.where(refined: true).count,
|
|
143
|
+
pending_vectors: HiveMindDocument.where(refined: false).count,
|
|
144
|
+
refinement_rate: calculate_refinement_rate,
|
|
145
|
+
last_activity: get_last_activity,
|
|
146
|
+
timestamp: Time.current
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
render json: stats
|
|
150
|
+
|
|
151
|
+
rescue => e
|
|
152
|
+
render json: {
|
|
153
|
+
error: 'Failed to generate stats',
|
|
154
|
+
message: e.message,
|
|
155
|
+
timestamp: Time.current
|
|
156
|
+
}, status: 500
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
private
|
|
161
|
+
|
|
162
|
+
def format_vector_for_gemini(vector)
|
|
163
|
+
{
|
|
164
|
+
id: vector.id,
|
|
165
|
+
content: vector.content,
|
|
166
|
+
source_type: vector.source_type,
|
|
167
|
+
source_id: vector.source_id,
|
|
168
|
+
metadata: vector.metadata || {},
|
|
169
|
+
created_at: vector.created_at,
|
|
170
|
+
content_length: vector.content&.length || 0,
|
|
171
|
+
preview: vector.content&.truncate(100)
|
|
172
|
+
}
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def refinement_template
|
|
176
|
+
{
|
|
177
|
+
instruction: "Refine each vector into atomic facts with keywords and generators",
|
|
178
|
+
chunking_rules: {
|
|
179
|
+
max_words_per_chunk: 50,
|
|
180
|
+
min_words_per_chunk: 10,
|
|
181
|
+
overlap_words: 5,
|
|
182
|
+
preserve_context: true
|
|
183
|
+
},
|
|
184
|
+
keyword_extraction: {
|
|
185
|
+
keywords_per_chunk: "3-5",
|
|
186
|
+
types: ["technical", "contextual", "semantic"],
|
|
187
|
+
importance_threshold: 0.6
|
|
188
|
+
},
|
|
189
|
+
generator_creation: {
|
|
190
|
+
pattern: "trigger_keywords → response_template",
|
|
191
|
+
confidence_threshold: 0.7,
|
|
192
|
+
max_generators_per_chunk: 3
|
|
193
|
+
},
|
|
194
|
+
output_format: {
|
|
195
|
+
chunks: "Array of atomic fact strings",
|
|
196
|
+
keywords: "Array of keyword strings",
|
|
197
|
+
generators: "Array of {trigger: [...], template: '...', confidence: 0.0-1.0}"
|
|
198
|
+
},
|
|
199
|
+
example: {
|
|
200
|
+
input: "Rails authentication with Devise requires configuration",
|
|
201
|
+
expected_output: {
|
|
202
|
+
chunks: ["Rails authentication with Devise requires configuration"],
|
|
203
|
+
keywords: ["rails", "authentication", "devise", "configuration"],
|
|
204
|
+
generators: [
|
|
205
|
+
{
|
|
206
|
+
trigger: ["rails", "authentication", "devise"],
|
|
207
|
+
template: "For Rails authentication, use Devise gem with proper configuration",
|
|
208
|
+
confidence: 0.85
|
|
209
|
+
}
|
|
210
|
+
]
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def calculate_refinement_rate
|
|
217
|
+
# Calculate vectors refined in last hour
|
|
218
|
+
one_hour_ago = 1.hour.ago
|
|
219
|
+
recent_refined = HiveMindDocument.where(refined: true)
|
|
220
|
+
.where('refined_at > ?', one_hour_ago)
|
|
221
|
+
.count
|
|
222
|
+
|
|
223
|
+
# Return per minute rate
|
|
224
|
+
(recent_refined / 60.0).round(2)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def get_last_activity
|
|
228
|
+
begin
|
|
229
|
+
last_refined = HiveMindDocument.where(refined: true)
|
|
230
|
+
.order(:refined_at)
|
|
231
|
+
.last
|
|
232
|
+
|
|
233
|
+
if last_refined&.refined_at
|
|
234
|
+
{
|
|
235
|
+
type: 'refinement',
|
|
236
|
+
timestamp: last_refined.refined_at,
|
|
237
|
+
vector_id: last_refined.id
|
|
238
|
+
}
|
|
239
|
+
else
|
|
240
|
+
{
|
|
241
|
+
type: 'none',
|
|
242
|
+
timestamp: nil,
|
|
243
|
+
vector_id: nil
|
|
244
|
+
}
|
|
245
|
+
end
|
|
246
|
+
rescue
|
|
247
|
+
{ type: 'error', timestamp: nil, vector_id: nil }
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def log_gemini_activity
|
|
252
|
+
activity_log = "#{Time.current.strftime('%H:%M:%S')} - #{action_name} - #{request.remote_ip}"
|
|
253
|
+
|
|
254
|
+
# Log to Gemini status file
|
|
255
|
+
File.open('/tmp/gemini_status.log', 'a') do |f|
|
|
256
|
+
f.puts "#{Time.current.strftime('%H:%M:%S')} - api - #{activity_log}"
|
|
257
|
+
end
|
|
258
|
+
rescue
|
|
259
|
+
# Ignore logging errors
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def log_gemini_status(level, message)
|
|
263
|
+
timestamp = Time.current.strftime('%H:%M:%S')
|
|
264
|
+
log_entry = "#{timestamp} - #{level} - #{message}"
|
|
265
|
+
|
|
266
|
+
# Log to Rails logger
|
|
267
|
+
case level
|
|
268
|
+
when 'error'
|
|
269
|
+
Rails.logger.error "[GEMINI] #{message}"
|
|
270
|
+
when 'success'
|
|
271
|
+
Rails.logger.info "[GEMINI] #{message}"
|
|
272
|
+
else
|
|
273
|
+
Rails.logger.debug "[GEMINI] #{message}"
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# Log to Gemini status file for dashboard
|
|
277
|
+
File.open('/tmp/gemini_status.log', 'a') do |f|
|
|
278
|
+
f.puts log_entry
|
|
279
|
+
end
|
|
280
|
+
rescue
|
|
281
|
+
# Ignore logging errors
|
|
282
|
+
end
|
|
283
|
+
end
|
|
@@ -44,7 +44,7 @@ module Hokipoki
|
|
|
44
44
|
endpoint: "http://localhost:3000/api/gemini/unrefined_vectors",
|
|
45
45
|
submit_endpoint: "http://localhost:3000/api/gemini/submit_refined",
|
|
46
46
|
batch_size: 10,
|
|
47
|
-
interval:
|
|
47
|
+
interval: 120
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
File.write('/tmp/gemini_refinement_template.json', template.to_json)
|
data/lib/hokipoki/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hokipoki
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rails Utilities
|
|
@@ -232,6 +232,7 @@ files:
|
|
|
232
232
|
- bin/gemini_refiner
|
|
233
233
|
- lib/generators/hive_mind/install_generator.rb
|
|
234
234
|
- lib/generators/hive_mind/start_generator.rb
|
|
235
|
+
- lib/generators/hive_mind/templates/api/gemini_controller.rb
|
|
235
236
|
- lib/generators/hive_mind/templates/create_hive_mind_documents.rb
|
|
236
237
|
- lib/generators/hive_mind/templates/embedding_service.rb
|
|
237
238
|
- lib/generators/hive_mind/templates/hive_mind_document.rb
|