hokipoki 0.8.4 → 0.8.6
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: b91046938bebd8651bae6ceae238830821314e7e76fc3a056b38f316f5f3afdf
|
|
4
|
+
data.tar.gz: 2cb95e0535b1dc51cf1e6eb9ccd294a11f7c56f71a36dbb598132c52b9adb811
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fa66e7e8197c2242eeec56e125cb79e2cd9e1c94d05c083aaac04c4668697afac8c75e471b6d9eb29238e5b9d1567d31b7a5a91697f1948593b4b346603ae364
|
|
7
|
+
data.tar.gz: a163960c56d505b79ed3dc7393c17e2568cc104785d98bd294f172c561392a6dbd2c0390da4ce37ff74c21cd89867516c2526e9f0b85abfb37f148a916ef254a
|
|
@@ -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
|
|
@@ -228,37 +228,38 @@ module Hokipoki
|
|
|
228
228
|
end
|
|
229
229
|
|
|
230
230
|
def display_next_steps
|
|
231
|
+
# Cool ASCII art for HOKIPOKI
|
|
232
|
+
ascii_art = <<~ASCII
|
|
233
|
+
██╗ ██╗ ██████╗ ██╗ ██╗██╗██████╗ ██████╗ ██╗ ██╗██╗
|
|
234
|
+
██║ ██║██╔═══██╗██║ ██╔╝██║██╔══██╗██╔═══██╗██║ ██╔╝██║
|
|
235
|
+
███████║██║ ██║█████╔╝ ██║██████╔╝██║ ██║█████╔╝ ██║
|
|
236
|
+
██╔══██║██║ ██║██╔═██╗ ██║██╔═══╝ ██║ ██║██╔═██╗ ██║
|
|
237
|
+
██║ ██║╚██████╔╝██║ ██╗██║██║ ╚██████╔╝██║ ██╗██║
|
|
238
|
+
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝
|
|
239
|
+
ASCII
|
|
240
|
+
|
|
241
|
+
say ascii_art, :cyan
|
|
242
|
+
say ""
|
|
231
243
|
say "🎉 HOKIPOKI CORE INSTALLATION COMPLETE!", :green
|
|
232
244
|
say "=" * 60, :green
|
|
233
245
|
say ""
|
|
234
|
-
say "
|
|
246
|
+
say "🚀 SUPER SIMPLE NEXT STEPS:", :cyan
|
|
235
247
|
say ""
|
|
236
248
|
say "1. 📦 Install dependencies:", :white
|
|
237
249
|
say " bundle install", :yellow
|
|
238
250
|
say ""
|
|
239
|
-
say "2.
|
|
240
|
-
say " EDITOR=nano rails credentials:edit", :yellow
|
|
241
|
-
say ""
|
|
242
|
-
say " Add this structure:", :white
|
|
243
|
-
say credentials_template, :yellow
|
|
244
|
-
say ""
|
|
245
|
-
say "3. 🗄️ Run database migrations:", :white
|
|
246
|
-
say " rails db:migrate", :yellow
|
|
247
|
-
say ""
|
|
248
|
-
say "4. 🧠 Install HiveMind intelligence:", :white
|
|
251
|
+
say "2. 🧠 One-command setup (installs everything):", :white
|
|
249
252
|
say " rails g hive_mind:install", :yellow
|
|
250
253
|
say ""
|
|
251
|
-
say "
|
|
252
|
-
say "
|
|
254
|
+
say " ✅ This automatically installs:", :green
|
|
255
|
+
say " - HiveMind vector database", :dim
|
|
256
|
+
say " - Parasite attachment for Claude", :dim
|
|
257
|
+
say " - Gemini refinement system", :dim
|
|
258
|
+
say " - Database migrations", :dim
|
|
253
259
|
say ""
|
|
254
|
-
say "
|
|
255
|
-
say " - If bundle fails: Check Ruby version compatibility", :white
|
|
256
|
-
say " - If credentials fail: Ensure master.key exists", :white
|
|
257
|
-
say " - If GitHub OAuth needed: Set up GitHub app first", :white
|
|
260
|
+
say "🎭 THAT'S IT! Everything else is automatic!", :magenta
|
|
258
261
|
say ""
|
|
259
|
-
say "
|
|
260
|
-
say " - GitHub OAuth setup: https://docs.github.com/en/apps/oauth-apps", :white
|
|
261
|
-
say " - Rails credentials: https://guides.rubyonrails.org/security.html#custom-credentials", :white
|
|
262
|
+
say "Next: Start Rails server and restart Claude to see the magic! ✨", :yellow
|
|
262
263
|
say ""
|
|
263
264
|
end
|
|
264
265
|
|
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.6
|
|
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
|