hokipoki 0.6.0 โ 0.7.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 +4 -4
- data/bin/gemini_refiner +354 -0
- data/lib/generators/hokipoki/attach_parasite_generator.rb +16 -2
- data/lib/hokipoki/cli/gemini_connector.rb +107 -0
- data/lib/hokipoki/cli/gemini_status_monitor.rb +220 -0
- data/lib/hokipoki/version.rb +1 -1
- data/lib/tasks/gemini.rake +194 -0
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a28a93f7a63fe34c78ad0a7a8cbafd7b580394706ad0aed259b1f5c2d7577f55
|
|
4
|
+
data.tar.gz: 8e848a028577835f20bf1b950b4089efc58d858ec88e2f4a8fc892539ba6f4e4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f7e2f1efc86028b124b4b3ef2e84fbf374c446321e8e6ad377f4bd97cff86e79751eb8edaa8e356b44f77495e6ad520643e453b98fa734cc9652c1d004df9b7d
|
|
7
|
+
data.tar.gz: 4d84834ef11b9cc98400cf9269e01df1ac6b89f2f2bc8d7162a1fc4f751ddf399e9d090916d2db0cc1c11c05c599dd1383663e17b9dec849d571f5f80f17e5b3
|
data/bin/gemini_refiner
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# Gemini Vector Refinement Engine
|
|
4
|
+
# This script runs in a separate terminal and handles vector refinement
|
|
5
|
+
|
|
6
|
+
require 'json'
|
|
7
|
+
require 'net/http'
|
|
8
|
+
require 'uri'
|
|
9
|
+
require 'time'
|
|
10
|
+
|
|
11
|
+
class GeminiRefiner
|
|
12
|
+
def initialize
|
|
13
|
+
@base_url = 'http://localhost:3000'
|
|
14
|
+
@template_file = '/tmp/gemini_refinement_template.json'
|
|
15
|
+
@status_file = '/tmp/gemini_status.log'
|
|
16
|
+
@current_refinement_file = '/tmp/gemini_current_refinement.json'
|
|
17
|
+
@batch_size = 10
|
|
18
|
+
@sleep_interval = 5
|
|
19
|
+
@refinement_count = 0
|
|
20
|
+
@start_time = Time.now
|
|
21
|
+
|
|
22
|
+
setup_logging
|
|
23
|
+
load_template
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def start
|
|
27
|
+
display_startup_banner
|
|
28
|
+
check_connectivity
|
|
29
|
+
|
|
30
|
+
log_status('info', 'Gemini refinement engine started')
|
|
31
|
+
puts "๐ Starting refinement loop..."
|
|
32
|
+
puts ""
|
|
33
|
+
|
|
34
|
+
main_refinement_loop
|
|
35
|
+
rescue Interrupt
|
|
36
|
+
puts "\n\n๐ Gemini refinement engine shutting down..."
|
|
37
|
+
cleanup
|
|
38
|
+
exit(0)
|
|
39
|
+
rescue => e
|
|
40
|
+
log_status('error', "Critical error: #{e.message}")
|
|
41
|
+
puts "โ Critical error: #{e.message}"
|
|
42
|
+
exit(1)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def setup_logging
|
|
48
|
+
# Initialize log file
|
|
49
|
+
File.write(@status_file, "")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def load_template
|
|
53
|
+
if File.exist?(@template_file)
|
|
54
|
+
@template = JSON.parse(File.read(@template_file))
|
|
55
|
+
puts "๐ Template loaded from #{@template_file}"
|
|
56
|
+
else
|
|
57
|
+
puts "โ ๏ธ Template file not found, using defaults"
|
|
58
|
+
@template = default_template
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def display_startup_banner
|
|
63
|
+
puts "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
64
|
+
puts "โ ๐ง GEMINI REFINEMENT ENGINE โ"
|
|
65
|
+
puts "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
66
|
+
puts ""
|
|
67
|
+
puts "๐ฏ Configuration:"
|
|
68
|
+
puts " Endpoint: #{@base_url}/api/gemini"
|
|
69
|
+
puts " Batch Size: #{@batch_size} vectors"
|
|
70
|
+
puts " Interval: #{@sleep_interval} seconds"
|
|
71
|
+
puts " Template: #{@template_file}"
|
|
72
|
+
puts ""
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def check_connectivity
|
|
76
|
+
puts "๐ก Testing connectivity..."
|
|
77
|
+
|
|
78
|
+
begin
|
|
79
|
+
uri = URI("#{@base_url}/api/gemini/health_check")
|
|
80
|
+
response = Net::HTTP.get_response(uri)
|
|
81
|
+
|
|
82
|
+
if response.code == '200'
|
|
83
|
+
puts " โ
API endpoint: Connected"
|
|
84
|
+
else
|
|
85
|
+
puts " โ ๏ธ API endpoint: #{response.code} #{response.message}"
|
|
86
|
+
end
|
|
87
|
+
rescue => e
|
|
88
|
+
puts " โ API endpoint: Connection failed (#{e.message})"
|
|
89
|
+
puts ""
|
|
90
|
+
puts "๐ง Troubleshooting:"
|
|
91
|
+
puts " - Make sure Rails server is running: rails server"
|
|
92
|
+
puts " - Check if the forge_generator app is accessible"
|
|
93
|
+
puts ""
|
|
94
|
+
exit(1)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Test Gemini CLI (mock for now)
|
|
98
|
+
if has_gemini_cli?
|
|
99
|
+
puts " โ
Gemini CLI: Available"
|
|
100
|
+
else
|
|
101
|
+
puts " โ ๏ธ Gemini CLI: Using mock refinement"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
puts ""
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def main_refinement_loop
|
|
108
|
+
loop do
|
|
109
|
+
begin
|
|
110
|
+
# Fetch unrefined vectors
|
|
111
|
+
vectors = fetch_unrefined_vectors
|
|
112
|
+
|
|
113
|
+
if vectors && vectors.any?
|
|
114
|
+
puts "๐ฅ Received #{vectors.count} vectors for refinement"
|
|
115
|
+
|
|
116
|
+
# Process each vector
|
|
117
|
+
refined_vectors = []
|
|
118
|
+
vectors.each_with_index do |vector, index|
|
|
119
|
+
refined = refine_vector(vector, index + 1, vectors.count)
|
|
120
|
+
refined_vectors << refined if refined
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Submit refined vectors
|
|
124
|
+
if refined_vectors.any?
|
|
125
|
+
submit_refined_vectors(refined_vectors)
|
|
126
|
+
@refinement_count += refined_vectors.count
|
|
127
|
+
|
|
128
|
+
# Update stats display
|
|
129
|
+
display_current_stats
|
|
130
|
+
end
|
|
131
|
+
else
|
|
132
|
+
puts "๐ค No vectors to refine... waiting #{@sleep_interval}s"
|
|
133
|
+
clear_current_refinement
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
sleep(@sleep_interval)
|
|
137
|
+
|
|
138
|
+
rescue => e
|
|
139
|
+
log_status('error', "Refinement loop error: #{e.message}")
|
|
140
|
+
puts "โ Error in refinement loop: #{e.message}"
|
|
141
|
+
puts " Retrying in #{@sleep_interval} seconds..."
|
|
142
|
+
sleep(@sleep_interval)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def fetch_unrefined_vectors
|
|
148
|
+
uri = URI("#{@base_url}/api/gemini/unrefined_vectors?batch_size=#{@batch_size}")
|
|
149
|
+
response = Net::HTTP.get_response(uri)
|
|
150
|
+
|
|
151
|
+
if response.code == '200'
|
|
152
|
+
data = JSON.parse(response.body)
|
|
153
|
+
data['vectors']
|
|
154
|
+
else
|
|
155
|
+
log_status('error', "Failed to fetch vectors: #{response.code}")
|
|
156
|
+
nil
|
|
157
|
+
end
|
|
158
|
+
rescue => e
|
|
159
|
+
log_status('error', "Network error fetching vectors: #{e.message}")
|
|
160
|
+
nil
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def refine_vector(vector, current_index, total_count)
|
|
164
|
+
vector_id = vector['id']
|
|
165
|
+
content = vector['content']
|
|
166
|
+
|
|
167
|
+
puts "๐ [#{current_index}/#{total_count}] Refining vector ##{vector_id}..."
|
|
168
|
+
|
|
169
|
+
# Update current refinement status
|
|
170
|
+
update_current_refinement(vector_id, content, current_index, total_count)
|
|
171
|
+
|
|
172
|
+
# Perform refinement (mock implementation for now)
|
|
173
|
+
refined_data = perform_gemini_refinement(content)
|
|
174
|
+
|
|
175
|
+
log_status('success', "Refined vector ##{vector_id} (#{refined_data[:keywords]&.count || 0} keywords)")
|
|
176
|
+
|
|
177
|
+
{
|
|
178
|
+
'id' => vector_id,
|
|
179
|
+
'chunks' => refined_data[:chunks],
|
|
180
|
+
'keywords' => refined_data[:keywords],
|
|
181
|
+
'generators' => refined_data[:generators]
|
|
182
|
+
}
|
|
183
|
+
rescue => e
|
|
184
|
+
log_status('error', "Failed to refine vector ##{vector_id}: #{e.message}")
|
|
185
|
+
puts " โ Error refining vector ##{vector_id}: #{e.message}"
|
|
186
|
+
nil
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def perform_gemini_refinement(content)
|
|
190
|
+
# Mock refinement implementation
|
|
191
|
+
# In real implementation, this would call Gemini API
|
|
192
|
+
|
|
193
|
+
words = content.split
|
|
194
|
+
chunks = []
|
|
195
|
+
keywords = []
|
|
196
|
+
|
|
197
|
+
# Simple chunking (50 words max)
|
|
198
|
+
words.each_slice(50) do |chunk_words|
|
|
199
|
+
chunk_text = chunk_words.join(' ')
|
|
200
|
+
chunks << chunk_text
|
|
201
|
+
|
|
202
|
+
# Extract keywords (simple implementation)
|
|
203
|
+
chunk_keywords = extract_keywords(chunk_text)
|
|
204
|
+
keywords.concat(chunk_keywords)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Create generators
|
|
208
|
+
generators = create_generators(keywords, chunks)
|
|
209
|
+
|
|
210
|
+
{
|
|
211
|
+
chunks: chunks,
|
|
212
|
+
keywords: keywords.uniq,
|
|
213
|
+
generators: generators
|
|
214
|
+
}
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def extract_keywords(text)
|
|
218
|
+
# Simple keyword extraction (mock)
|
|
219
|
+
words = text.downcase.split(/\W+/)
|
|
220
|
+
|
|
221
|
+
# Filter meaningful words (longer than 3 chars, not common words)
|
|
222
|
+
common_words = %w[the and for are but not you all can had her was one our out day get has him how its may new now old see two way who boy did man its can all]
|
|
223
|
+
|
|
224
|
+
meaningful_words = words.select do |word|
|
|
225
|
+
word.length > 3 && !common_words.include?(word)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Return top 5 most frequent
|
|
229
|
+
meaningful_words.tally.sort_by { |_, count| -count }.first(5).map(&:first)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def create_generators(keywords, chunks)
|
|
233
|
+
generators = []
|
|
234
|
+
|
|
235
|
+
# Create one generator per chunk with its keywords
|
|
236
|
+
chunks.each_with_index do |chunk, index|
|
|
237
|
+
chunk_keywords = keywords.sample(3) # Use 3 random keywords
|
|
238
|
+
|
|
239
|
+
generators << {
|
|
240
|
+
'trigger' => chunk_keywords,
|
|
241
|
+
'template' => "Based on the context: #{chunk.truncate(100)}",
|
|
242
|
+
'confidence' => 0.7 + (rand * 0.3) # Random confidence 0.7-1.0
|
|
243
|
+
}
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
generators
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def submit_refined_vectors(refined_vectors)
|
|
250
|
+
uri = URI("#{@base_url}/api/gemini/submit_refined")
|
|
251
|
+
|
|
252
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
253
|
+
request = Net::HTTP::Post.new(uri)
|
|
254
|
+
request['Content-Type'] = 'application/json'
|
|
255
|
+
request.body = { vectors: refined_vectors }.to_json
|
|
256
|
+
|
|
257
|
+
response = http.request(request)
|
|
258
|
+
|
|
259
|
+
if response.code == '200'
|
|
260
|
+
puts "โ
Successfully submitted #{refined_vectors.count} refined vectors"
|
|
261
|
+
log_status('success', "Submitted #{refined_vectors.count} refined vectors")
|
|
262
|
+
else
|
|
263
|
+
puts "โ ๏ธ Submission warning: #{response.code} #{response.message}"
|
|
264
|
+
log_status('error', "Submission failed: #{response.code}")
|
|
265
|
+
end
|
|
266
|
+
rescue => e
|
|
267
|
+
puts "โ Failed to submit refined vectors: #{e.message}"
|
|
268
|
+
log_status('error', "Submission error: #{e.message}")
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def update_current_refinement(vector_id, content, current, total)
|
|
272
|
+
progress = ((current.to_f / total) * 100).round
|
|
273
|
+
|
|
274
|
+
current_data = {
|
|
275
|
+
'id' => vector_id,
|
|
276
|
+
'content' => content,
|
|
277
|
+
'progress' => progress,
|
|
278
|
+
'current' => current,
|
|
279
|
+
'total' => total,
|
|
280
|
+
'updated_at' => Time.now.iso8601
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
File.write(@current_refinement_file, current_data.to_json)
|
|
284
|
+
rescue
|
|
285
|
+
# Ignore file write errors
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def clear_current_refinement
|
|
289
|
+
File.delete(@current_refinement_file) if File.exist?(@current_refinement_file)
|
|
290
|
+
rescue
|
|
291
|
+
# Ignore file delete errors
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def display_current_stats
|
|
295
|
+
runtime = Time.now - @start_time
|
|
296
|
+
rate = @refinement_count / (runtime / 60.0) # per minute
|
|
297
|
+
|
|
298
|
+
puts ""
|
|
299
|
+
puts "๐ Session Stats:"
|
|
300
|
+
puts " Refined: #{@refinement_count} vectors"
|
|
301
|
+
puts " Runtime: #{(runtime / 60).round(1)} minutes"
|
|
302
|
+
puts " Rate: #{rate.round(1)}/min"
|
|
303
|
+
puts ""
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def log_status(level, message)
|
|
307
|
+
timestamp = Time.now.strftime('%H:%M:%S')
|
|
308
|
+
log_entry = "#{timestamp} - #{level} - #{message}"
|
|
309
|
+
|
|
310
|
+
File.open(@status_file, 'a') do |f|
|
|
311
|
+
f.puts log_entry
|
|
312
|
+
end
|
|
313
|
+
rescue
|
|
314
|
+
# Ignore logging errors
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def has_gemini_cli?
|
|
318
|
+
system('which gemini > /dev/null 2>&1') ||
|
|
319
|
+
system('which google-ai > /dev/null 2>&1') ||
|
|
320
|
+
ENV['GEMINI_API_KEY'] || ENV['GOOGLE_API_KEY']
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def default_template
|
|
324
|
+
{
|
|
325
|
+
'mode' => 'vector_refinement',
|
|
326
|
+
'instructions' => {
|
|
327
|
+
'primary' => 'Refine each vector into atomic facts with keywords',
|
|
328
|
+
'chunking' => {
|
|
329
|
+
'max_words' => 50,
|
|
330
|
+
'create_generators' => true,
|
|
331
|
+
'keyword_density' => '3-5 per chunk'
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def cleanup
|
|
338
|
+
clear_current_refinement
|
|
339
|
+
log_status('info', 'Gemini refinement engine stopped')
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# String truncate method
|
|
344
|
+
class String
|
|
345
|
+
def truncate(length)
|
|
346
|
+
self.length > length ? "#{self[0..length-3]}..." : self
|
|
347
|
+
end unless method_defined?(:truncate)
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# Start the refiner
|
|
351
|
+
if __FILE__ == $0
|
|
352
|
+
refiner = GeminiRefiner.new
|
|
353
|
+
refiner.start
|
|
354
|
+
end
|
|
@@ -306,12 +306,26 @@ module Hokipoki
|
|
|
306
306
|
config_addition = <<~RUBY
|
|
307
307
|
|
|
308
308
|
# Parasite attachment enabled
|
|
309
|
-
|
|
310
|
-
|
|
309
|
+
Rails.application.configure do |config|
|
|
310
|
+
config.parasite_attachment = true
|
|
311
|
+
config.parasite_type = '#{options[:parasite_type]}'
|
|
312
|
+
end
|
|
311
313
|
RUBY
|
|
312
314
|
|
|
313
315
|
append_to_file main_config_file, config_addition
|
|
314
316
|
say "๐ Updated main hokipoki config", :green
|
|
317
|
+
else
|
|
318
|
+
# Create the config file if it doesn't exist
|
|
319
|
+
create_file main_config_file, <<~RUBY
|
|
320
|
+
# HokiPoki Configuration
|
|
321
|
+
|
|
322
|
+
Rails.application.configure do |config|
|
|
323
|
+
# Parasite attachment enabled
|
|
324
|
+
config.parasite_attachment = true
|
|
325
|
+
config.parasite_type = '#{options[:parasite_type]}'
|
|
326
|
+
end
|
|
327
|
+
RUBY
|
|
328
|
+
say "๐ Created hokipoki config with parasite settings", :green
|
|
315
329
|
end
|
|
316
330
|
end
|
|
317
331
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
module Hokipoki
|
|
2
|
+
module CLI
|
|
3
|
+
class GeminiConnector
|
|
4
|
+
def self.start
|
|
5
|
+
puts "๐ Starting Gemini Vector Refinement Engine..."
|
|
6
|
+
puts ""
|
|
7
|
+
|
|
8
|
+
# 1. Create refinement template
|
|
9
|
+
create_refinement_template
|
|
10
|
+
|
|
11
|
+
# 2. Create communication pipes
|
|
12
|
+
setup_communication_pipes
|
|
13
|
+
|
|
14
|
+
# 3. Open new terminal with Gemini
|
|
15
|
+
terminal_cmd = build_terminal_command
|
|
16
|
+
puts "๐ก Opening Gemini terminal..."
|
|
17
|
+
system(terminal_cmd)
|
|
18
|
+
|
|
19
|
+
# 4. Start monitoring dashboard in current terminal
|
|
20
|
+
sleep(2) # Give terminal time to open
|
|
21
|
+
puts "๐ฏ Starting refinement dashboard..."
|
|
22
|
+
puts ""
|
|
23
|
+
show_refinement_dashboard
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def self.create_refinement_template
|
|
29
|
+
template = {
|
|
30
|
+
mode: "vector_refinement",
|
|
31
|
+
instructions: {
|
|
32
|
+
primary: "Refine each vector into atomic facts with keywords",
|
|
33
|
+
chunking: {
|
|
34
|
+
max_words: 50,
|
|
35
|
+
create_generators: true,
|
|
36
|
+
keyword_density: "3-5 per chunk"
|
|
37
|
+
},
|
|
38
|
+
output_format: {
|
|
39
|
+
chunks: "array of atomic facts",
|
|
40
|
+
keywords: "array of trigger words",
|
|
41
|
+
generators: "keyword โ response patterns"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
endpoint: "http://localhost:3000/api/gemini/unrefined_vectors",
|
|
45
|
+
submit_endpoint: "http://localhost:3000/api/gemini/submit_refined",
|
|
46
|
+
batch_size: 10,
|
|
47
|
+
interval: 5
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
File.write('/tmp/gemini_refinement_template.json', template.to_json)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.setup_communication_pipes
|
|
54
|
+
# Create named pipes for communication
|
|
55
|
+
system("mkfifo /tmp/gemini_status.fifo 2>/dev/null || true")
|
|
56
|
+
system("mkfifo /tmp/gemini_refined_vectors.fifo 2>/dev/null || true")
|
|
57
|
+
|
|
58
|
+
# Create status file
|
|
59
|
+
File.write('/tmp/gemini_status.log', "")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.build_terminal_command
|
|
63
|
+
# Get the gem's bin directory
|
|
64
|
+
gem_bin_path = File.expand_path('../../../../bin/gemini_refiner', __FILE__)
|
|
65
|
+
|
|
66
|
+
gemini_script = <<~SCRIPT
|
|
67
|
+
clear
|
|
68
|
+
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
69
|
+
echo " ๐ง GEMINI VECTOR REFINEMENT ENGINE"
|
|
70
|
+
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
71
|
+
echo ""
|
|
72
|
+
echo "๐ก Connecting to HiveMind at http://localhost:3000"
|
|
73
|
+
echo "๐ฏ Template: /tmp/gemini_refinement_template.json"
|
|
74
|
+
echo "โก Starting refinement loop..."
|
|
75
|
+
echo ""
|
|
76
|
+
|
|
77
|
+
# Run the gemini refiner script
|
|
78
|
+
#{gem_bin_path}
|
|
79
|
+
SCRIPT
|
|
80
|
+
|
|
81
|
+
# Write script to temp file
|
|
82
|
+
script_path = '/tmp/start_gemini_refiner.sh'
|
|
83
|
+
File.write(script_path, gemini_script)
|
|
84
|
+
system("chmod +x #{script_path}")
|
|
85
|
+
|
|
86
|
+
# Open in new terminal (works on macOS and Linux)
|
|
87
|
+
if RUBY_PLATFORM =~ /darwin/
|
|
88
|
+
# macOS
|
|
89
|
+
"osascript -e 'tell app \"Terminal\" to do script \"#{script_path}\"'"
|
|
90
|
+
elsif ENV['DISPLAY']
|
|
91
|
+
# Linux with GUI
|
|
92
|
+
"gnome-terminal -- bash -c \"#{script_path}; exec bash\" || xterm -e \"#{script_path}; exec bash\""
|
|
93
|
+
else
|
|
94
|
+
# Fallback - run in background and show message
|
|
95
|
+
puts "โ ๏ธ GUI terminal not available. Run this in a separate terminal:"
|
|
96
|
+
puts " #{script_path}"
|
|
97
|
+
return "echo 'Run #{script_path} in separate terminal'"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def self.show_refinement_dashboard
|
|
102
|
+
require_relative 'gemini_status_monitor'
|
|
103
|
+
GeminiStatusMonitor.show
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
module Hokipoki
|
|
2
|
+
module CLI
|
|
3
|
+
class GeminiStatusMonitor
|
|
4
|
+
def self.show
|
|
5
|
+
puts "๐ฏ Starting Gemini Refinement Dashboard..."
|
|
6
|
+
sleep(1)
|
|
7
|
+
|
|
8
|
+
loop do
|
|
9
|
+
clear_screen
|
|
10
|
+
display_header
|
|
11
|
+
display_stats
|
|
12
|
+
display_current_work
|
|
13
|
+
display_activity_log
|
|
14
|
+
display_controls
|
|
15
|
+
sleep(2)
|
|
16
|
+
end
|
|
17
|
+
rescue Interrupt
|
|
18
|
+
puts "\n\n๐ Gemini refinement dashboard stopped."
|
|
19
|
+
cleanup_temp_files
|
|
20
|
+
exit(0)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def self.clear_screen
|
|
26
|
+
system('clear') || system('cls')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.display_header
|
|
30
|
+
puts "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
31
|
+
puts "โ ๐ง GEMINI VECTOR REFINEMENT DASHBOARD โ"
|
|
32
|
+
puts "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
33
|
+
puts ""
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.display_stats
|
|
37
|
+
stats = fetch_refinement_stats
|
|
38
|
+
|
|
39
|
+
puts "๐ REFINEMENT STATS"
|
|
40
|
+
puts "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
41
|
+
puts " Total Vectors: #{stats[:total_vectors]}"
|
|
42
|
+
puts " Refined: #{stats[:refined_count]} โ
"
|
|
43
|
+
puts " Pending: #{stats[:pending_count]} โณ"
|
|
44
|
+
puts " Processing Rate: #{stats[:rate]}/min"
|
|
45
|
+
puts " Last Updated: #{Time.current.strftime('%H:%M:%S')}"
|
|
46
|
+
puts ""
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.display_current_work
|
|
50
|
+
current = fetch_current_refinement
|
|
51
|
+
|
|
52
|
+
if current
|
|
53
|
+
puts "๐ CURRENTLY REFINING"
|
|
54
|
+
puts "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
55
|
+
puts " Vector ID: #{current[:id]}"
|
|
56
|
+
puts " Content: #{truncate_text(current[:content], 60)}"
|
|
57
|
+
puts " Progress: #{progress_bar(current[:progress])}"
|
|
58
|
+
puts ""
|
|
59
|
+
else
|
|
60
|
+
puts "๐ค IDLE - Waiting for vectors to refine..."
|
|
61
|
+
puts ""
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.display_activity_log
|
|
66
|
+
puts "๐ RECENT ACTIVITY"
|
|
67
|
+
puts "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
68
|
+
|
|
69
|
+
logs = recent_logs
|
|
70
|
+
if logs.empty?
|
|
71
|
+
puts " ๐ No recent activity - system initializing..."
|
|
72
|
+
else
|
|
73
|
+
logs.last(5).each do |log|
|
|
74
|
+
icon = case log[:status]
|
|
75
|
+
when 'success' then 'โ
'
|
|
76
|
+
when 'error' then 'โ'
|
|
77
|
+
when 'processing' then '๐'
|
|
78
|
+
else '๐'
|
|
79
|
+
end
|
|
80
|
+
puts " #{icon} [#{log[:time]}] #{log[:message]}"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
puts ""
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def self.display_controls
|
|
87
|
+
puts "๐ฎ CONTROLS"
|
|
88
|
+
puts "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
89
|
+
puts " Ctrl+C: Stop dashboard and exit"
|
|
90
|
+
puts " Dashboard auto-refreshes every 2 seconds"
|
|
91
|
+
puts ""
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def self.fetch_refinement_stats
|
|
95
|
+
begin
|
|
96
|
+
if defined?(Rails) && defined?(HiveMindDocument)
|
|
97
|
+
total = HiveMindDocument.count
|
|
98
|
+
refined = HiveMindDocument.where(refined: true).count
|
|
99
|
+
pending = total - refined
|
|
100
|
+
|
|
101
|
+
# Calculate processing rate from recent activity
|
|
102
|
+
rate = calculate_processing_rate
|
|
103
|
+
|
|
104
|
+
{
|
|
105
|
+
total_vectors: total,
|
|
106
|
+
refined_count: refined,
|
|
107
|
+
pending_count: pending,
|
|
108
|
+
rate: rate
|
|
109
|
+
}
|
|
110
|
+
else
|
|
111
|
+
{
|
|
112
|
+
total_vectors: 0,
|
|
113
|
+
refined_count: 0,
|
|
114
|
+
pending_count: 0,
|
|
115
|
+
rate: 0
|
|
116
|
+
}
|
|
117
|
+
end
|
|
118
|
+
rescue => e
|
|
119
|
+
{
|
|
120
|
+
total_vectors: "Error",
|
|
121
|
+
refined_count: "Error",
|
|
122
|
+
pending_count: "Error",
|
|
123
|
+
rate: 0
|
|
124
|
+
}
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def self.fetch_current_refinement
|
|
129
|
+
begin
|
|
130
|
+
# Check if there's a current refinement status
|
|
131
|
+
status_file = '/tmp/gemini_current_refinement.json'
|
|
132
|
+
if File.exist?(status_file)
|
|
133
|
+
current_data = JSON.parse(File.read(status_file))
|
|
134
|
+
return {
|
|
135
|
+
id: current_data['id'],
|
|
136
|
+
content: current_data['content'],
|
|
137
|
+
progress: current_data['progress'] || 0
|
|
138
|
+
}
|
|
139
|
+
end
|
|
140
|
+
rescue => e
|
|
141
|
+
# Ignore errors, just return nil
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
nil
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def self.recent_logs
|
|
148
|
+
begin
|
|
149
|
+
log_file = '/tmp/gemini_status.log'
|
|
150
|
+
return [] unless File.exist?(log_file)
|
|
151
|
+
|
|
152
|
+
File.readlines(log_file).map do |line|
|
|
153
|
+
next nil if line.strip.empty?
|
|
154
|
+
|
|
155
|
+
parts = line.strip.split(' - ', 3)
|
|
156
|
+
next nil if parts.length < 3
|
|
157
|
+
|
|
158
|
+
{
|
|
159
|
+
time: parts[0],
|
|
160
|
+
status: parts[1],
|
|
161
|
+
message: parts[2]
|
|
162
|
+
}
|
|
163
|
+
end.compact
|
|
164
|
+
rescue => e
|
|
165
|
+
[]
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def self.calculate_processing_rate
|
|
170
|
+
begin
|
|
171
|
+
logs = recent_logs
|
|
172
|
+
successful_logs = logs.select { |log| log[:status] == 'success' }
|
|
173
|
+
|
|
174
|
+
# Count successes in last 5 minutes
|
|
175
|
+
five_min_ago = Time.current - 5.minutes
|
|
176
|
+
recent_successes = successful_logs.select do |log|
|
|
177
|
+
begin
|
|
178
|
+
log_time = Time.parse(log[:time])
|
|
179
|
+
log_time > five_min_ago
|
|
180
|
+
rescue
|
|
181
|
+
false
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Convert to per-minute rate
|
|
186
|
+
(recent_successes.count * 12) / 10.0 # Approximate rate per minute
|
|
187
|
+
rescue => e
|
|
188
|
+
0
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def self.progress_bar(percent)
|
|
193
|
+
return "[โโโโโโโโโโโโโโโโโโโโ] 0%" if percent.nil? || percent == 0
|
|
194
|
+
|
|
195
|
+
filled = 'โ' * (percent / 5).to_i
|
|
196
|
+
empty = 'โ' * (20 - (percent / 5).to_i)
|
|
197
|
+
"[#{filled}#{empty}] #{percent}%"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def self.truncate_text(text, length)
|
|
201
|
+
return "" if text.nil?
|
|
202
|
+
text.length > length ? "#{text[0..length-3]}..." : text
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def self.cleanup_temp_files
|
|
206
|
+
temp_files = [
|
|
207
|
+
'/tmp/gemini_status.fifo',
|
|
208
|
+
'/tmp/gemini_refined_vectors.fifo',
|
|
209
|
+
'/tmp/gemini_current_refinement.json'
|
|
210
|
+
]
|
|
211
|
+
|
|
212
|
+
temp_files.each do |file|
|
|
213
|
+
File.delete(file) if File.exist?(file)
|
|
214
|
+
rescue
|
|
215
|
+
# Ignore cleanup errors
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
data/lib/hokipoki/version.rb
CHANGED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
namespace :gemini do
|
|
2
|
+
desc "Start Gemini vector refinement engine in new terminal"
|
|
3
|
+
task :start => :environment do
|
|
4
|
+
require_relative '../hokipoki/cli/gemini_connector'
|
|
5
|
+
|
|
6
|
+
puts "๐ GEMINI VECTOR REFINEMENT SYSTEM"
|
|
7
|
+
puts "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
8
|
+
puts ""
|
|
9
|
+
puts "๐ Pre-flight checks:"
|
|
10
|
+
|
|
11
|
+
# Check if Rails is available
|
|
12
|
+
if defined?(Rails)
|
|
13
|
+
puts " โ
Rails environment loaded"
|
|
14
|
+
else
|
|
15
|
+
puts " โ Rails not available"
|
|
16
|
+
exit(1)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Check if HiveMindDocument model exists
|
|
20
|
+
if defined?(HiveMindDocument)
|
|
21
|
+
doc_count = HiveMindDocument.count rescue 0
|
|
22
|
+
puts " โ
HiveMindDocument available (#{doc_count} vectors)"
|
|
23
|
+
else
|
|
24
|
+
puts " โ ๏ธ HiveMindDocument not available (will work but no data)"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Check if Rails server is running
|
|
28
|
+
begin
|
|
29
|
+
require 'net/http'
|
|
30
|
+
response = Net::HTTP.get_response(URI('http://localhost:3000/'))
|
|
31
|
+
puts " โ
Rails server running on port 3000"
|
|
32
|
+
rescue
|
|
33
|
+
puts " โ ๏ธ Rails server not detected on port 3000"
|
|
34
|
+
puts " Starting Rails server in background..."
|
|
35
|
+
|
|
36
|
+
# Try to start Rails server in background
|
|
37
|
+
Thread.new do
|
|
38
|
+
system("cd #{Rails.root} && rails server -d")
|
|
39
|
+
end
|
|
40
|
+
sleep(3)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
puts ""
|
|
44
|
+
puts "๐ฏ Starting Gemini refinement system..."
|
|
45
|
+
puts ""
|
|
46
|
+
|
|
47
|
+
# Start the Gemini connector
|
|
48
|
+
Hokipoki::CLI::GeminiConnector.start
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
desc "Show Gemini refinement status"
|
|
52
|
+
task :status => :environment do
|
|
53
|
+
require_relative '../hokipoki/cli/gemini_status_monitor'
|
|
54
|
+
|
|
55
|
+
puts "๐ GEMINI REFINEMENT STATUS"
|
|
56
|
+
puts "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
57
|
+
puts ""
|
|
58
|
+
|
|
59
|
+
# Show current status without the interactive dashboard
|
|
60
|
+
stats = fetch_quick_stats
|
|
61
|
+
|
|
62
|
+
puts "๐ Quick Stats:"
|
|
63
|
+
puts " Total Vectors: #{stats[:total_vectors]}"
|
|
64
|
+
puts " Refined: #{stats[:refined_count]} โ
"
|
|
65
|
+
puts " Pending: #{stats[:pending_count]} โณ"
|
|
66
|
+
puts ""
|
|
67
|
+
|
|
68
|
+
# Check if Gemini process is running
|
|
69
|
+
gemini_running = system('pgrep -f "gemini_refiner" > /dev/null')
|
|
70
|
+
if gemini_running
|
|
71
|
+
puts "๐ Gemini refiner: RUNNING"
|
|
72
|
+
else
|
|
73
|
+
puts "๐ค Gemini refiner: STOPPED"
|
|
74
|
+
puts ""
|
|
75
|
+
puts " To start: rails gemini:start"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
puts ""
|
|
79
|
+
puts " For live dashboard: rails gemini:start"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
desc "Stop Gemini refinement engine"
|
|
83
|
+
task :stop => :environment do
|
|
84
|
+
puts "๐ Stopping Gemini refinement engine..."
|
|
85
|
+
|
|
86
|
+
# Kill Gemini processes
|
|
87
|
+
system('pkill -f "gemini_refiner"')
|
|
88
|
+
|
|
89
|
+
# Clean up temp files
|
|
90
|
+
temp_files = [
|
|
91
|
+
'/tmp/gemini_status.fifo',
|
|
92
|
+
'/tmp/gemini_refined_vectors.fifo',
|
|
93
|
+
'/tmp/gemini_current_refinement.json',
|
|
94
|
+
'/tmp/gemini_refinement_template.json',
|
|
95
|
+
'/tmp/gemini_status.log',
|
|
96
|
+
'/tmp/start_gemini_refiner.sh'
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
temp_files.each do |file|
|
|
100
|
+
File.delete(file) if File.exist?(file)
|
|
101
|
+
rescue
|
|
102
|
+
# Ignore cleanup errors
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
puts "โ
Gemini refinement engine stopped"
|
|
106
|
+
puts "๐งน Temporary files cleaned up"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
desc "Test Gemini API connection"
|
|
110
|
+
task :test => :environment do
|
|
111
|
+
puts "๐งช GEMINI API CONNECTION TEST"
|
|
112
|
+
puts "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
|
|
113
|
+
puts ""
|
|
114
|
+
|
|
115
|
+
# Test basic connectivity
|
|
116
|
+
begin
|
|
117
|
+
require 'net/http'
|
|
118
|
+
require 'json'
|
|
119
|
+
|
|
120
|
+
# Test unrefined vectors endpoint
|
|
121
|
+
puts "๐ก Testing API endpoints..."
|
|
122
|
+
|
|
123
|
+
uri = URI('http://localhost:3000/api/gemini/unrefined_vectors')
|
|
124
|
+
response = Net::HTTP.get_response(uri)
|
|
125
|
+
|
|
126
|
+
if response.code == '200'
|
|
127
|
+
puts " โ
Unrefined vectors endpoint: OK"
|
|
128
|
+
data = JSON.parse(response.body)
|
|
129
|
+
puts " Found #{data['vectors']&.count || 0} vectors"
|
|
130
|
+
else
|
|
131
|
+
puts " โ Unrefined vectors endpoint: FAILED (#{response.code})"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
rescue => e
|
|
135
|
+
puts " โ API test failed: #{e.message}"
|
|
136
|
+
puts ""
|
|
137
|
+
puts " ๐ง Troubleshooting:"
|
|
138
|
+
puts " - Make sure Rails server is running: rails server"
|
|
139
|
+
puts " - Check if API routes are configured"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Test Gemini CLI availability
|
|
143
|
+
puts ""
|
|
144
|
+
puts "๐ Testing Gemini CLI..."
|
|
145
|
+
|
|
146
|
+
if system('which gemini > /dev/null 2>&1')
|
|
147
|
+
puts " โ
Gemini CLI found"
|
|
148
|
+
|
|
149
|
+
# Test Gemini API key
|
|
150
|
+
if ENV['GEMINI_API_KEY'] || ENV['GOOGLE_API_KEY']
|
|
151
|
+
puts " โ
API key configured"
|
|
152
|
+
else
|
|
153
|
+
puts " โ ๏ธ API key not found in environment"
|
|
154
|
+
puts " Set GEMINI_API_KEY or GOOGLE_API_KEY"
|
|
155
|
+
end
|
|
156
|
+
else
|
|
157
|
+
puts " โ Gemini CLI not found"
|
|
158
|
+
puts " Install with: npm install -g @google/generative-ai"
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
puts ""
|
|
162
|
+
puts "๐ฏ Test complete!"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
private
|
|
166
|
+
|
|
167
|
+
def fetch_quick_stats
|
|
168
|
+
begin
|
|
169
|
+
if defined?(HiveMindDocument)
|
|
170
|
+
total = HiveMindDocument.count
|
|
171
|
+
refined = HiveMindDocument.where(refined: true).count
|
|
172
|
+
pending = total - refined
|
|
173
|
+
|
|
174
|
+
{
|
|
175
|
+
total_vectors: total,
|
|
176
|
+
refined_count: refined,
|
|
177
|
+
pending_count: pending
|
|
178
|
+
}
|
|
179
|
+
else
|
|
180
|
+
{
|
|
181
|
+
total_vectors: 0,
|
|
182
|
+
refined_count: 0,
|
|
183
|
+
pending_count: 0
|
|
184
|
+
}
|
|
185
|
+
end
|
|
186
|
+
rescue => e
|
|
187
|
+
{
|
|
188
|
+
total_vectors: "Error",
|
|
189
|
+
refined_count: "Error",
|
|
190
|
+
pending_count: "Error"
|
|
191
|
+
}
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
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.
|
|
4
|
+
version: 0.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rails Utilities
|
|
@@ -209,11 +209,13 @@ description: A collection of utilities and enhancements for Rails applications i
|
|
|
209
209
|
database optimizations, background processing helpers, and developer tools.
|
|
210
210
|
email:
|
|
211
211
|
- utilities@example.com
|
|
212
|
-
executables:
|
|
212
|
+
executables:
|
|
213
|
+
- gemini_refiner
|
|
213
214
|
extensions: []
|
|
214
215
|
extra_rdoc_files: []
|
|
215
216
|
files:
|
|
216
217
|
- LICENSE
|
|
218
|
+
- bin/gemini_refiner
|
|
217
219
|
- lib/generators/hive_mind/install_generator.rb
|
|
218
220
|
- lib/generators/hive_mind/start_generator.rb
|
|
219
221
|
- lib/generators/hive_mind/templates/create_hive_mind_documents.rb
|
|
@@ -232,6 +234,8 @@ files:
|
|
|
232
234
|
- lib/hokipoki/claude/parasite.rb
|
|
233
235
|
- lib/hokipoki/claude/thought_interceptor.rb
|
|
234
236
|
- lib/hokipoki/claude_auto_loader.rb
|
|
237
|
+
- lib/hokipoki/cli/gemini_connector.rb
|
|
238
|
+
- lib/hokipoki/cli/gemini_status_monitor.rb
|
|
235
239
|
- lib/hokipoki/configuration.rb
|
|
236
240
|
- lib/hokipoki/console.rb
|
|
237
241
|
- lib/hokipoki/engine.rb
|
|
@@ -247,6 +251,7 @@ files:
|
|
|
247
251
|
- lib/hokipoki/template_store.rb
|
|
248
252
|
- lib/hokipoki/vector_engine.rb
|
|
249
253
|
- lib/hokipoki/version.rb
|
|
254
|
+
- lib/tasks/gemini.rake
|
|
250
255
|
homepage: https://github.com/rails-utilities/hokipoki
|
|
251
256
|
licenses:
|
|
252
257
|
- Proprietary
|