hokipoki 0.5.1 ā 0.7.0
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/hive_mind/install_generator.rb +19 -9
- data/lib/generators/hokipoki/install_generator.rb +22 -33
- data/lib/hokipoki/atomic_fact_extractor.rb +1 -1
- data/lib/hokipoki/cli/gemini_connector.rb +107 -0
- data/lib/hokipoki/cli/gemini_status_monitor.rb +220 -0
- data/lib/hokipoki/configuration.rb +54 -2
- data/lib/hokipoki/vector_engine.rb +132 -3
- data/lib/hokipoki/version.rb +1 -1
- data/lib/hokipoki.rb +156 -1
- data/lib/tasks/gemini.rake +194 -0
- metadata +7 -58
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4fdce824f42ae5123c16881e6750eea924cff8b6b2cd498f4329050411994d18
|
|
4
|
+
data.tar.gz: 8b150ca5b979b06b4265db8c0cdb873045dece1d85b39ac440b436919a096bd0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '018c838374788cbd86af2fafe917568925b59cf6e137026c35326b4f2d137a4fe585939367c5c7935ac1e5719bd026a8ebe909742be45a45cf9e28a23b303bf9'
|
|
7
|
+
data.tar.gz: 216d2b1790a380a03e68c7895e450442679c00cb766226c3dc5c84d3cc0f442c2e18e4332d76a8463e7c5ae2438e753bce140767ef7bd722a91892a16973507e
|
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
|
|
@@ -197,7 +197,7 @@ module HiveMind
|
|
|
197
197
|
|
|
198
198
|
def display_completion_message
|
|
199
199
|
say "\n#{@pastel.green.bold('ā
HokiPoki lightweight installation completed!')}"
|
|
200
|
-
say "\n#{@pastel.cyan.bold('šÆ
|
|
200
|
+
say "\n#{@pastel.cyan.bold('šÆ ESSENTIAL NEXT STEPS - START SERVICES:')}"
|
|
201
201
|
|
|
202
202
|
say "\n #{@pastel.yellow('1. Install gem dependencies:')}"
|
|
203
203
|
say " #{@pastel.cyan('bundle install')}"
|
|
@@ -205,16 +205,26 @@ module HiveMind
|
|
|
205
205
|
say "\n #{@pastel.yellow('2. Run database migrations:')}"
|
|
206
206
|
say " #{@pastel.cyan('rails db:migrate')}"
|
|
207
207
|
|
|
208
|
-
say "\n #{@pastel.yellow('3.
|
|
209
|
-
say " #{@pastel.cyan('
|
|
210
|
-
say " #{@pastel.
|
|
211
|
-
say " #{@pastel.dim('OR if already in Claude, exit and re-enter')}"
|
|
208
|
+
say "\n #{@pastel.yellow('3. š START RAILS SERVER (REQUIRED):')}"
|
|
209
|
+
say " #{@pastel.cyan('rails server')} #{@pastel.dim('(Keep this running in background)')}"
|
|
210
|
+
say " #{@pastel.dim('š This enables HiveMind connection for Claude')}"
|
|
212
211
|
|
|
213
|
-
say "\n #{@pastel.yellow('4.
|
|
214
|
-
say " #{@pastel.
|
|
212
|
+
say "\n #{@pastel.yellow('4. š§ START HIVEMIND CONNECTION:')}"
|
|
213
|
+
say " #{@pastel.cyan('rails g hive_mind:start')} #{@pastel.dim('(Run this to establish Claude link)')}"
|
|
214
|
+
say " #{@pastel.dim('š Creates bin/hive_mind_connect script')}"
|
|
215
215
|
|
|
216
|
-
say "\n #{@pastel.yellow('5.
|
|
217
|
-
say " #{@pastel.
|
|
216
|
+
say "\n #{@pastel.yellow('5. š¦ ACTIVATE CLAUDE PARASITE:')}"
|
|
217
|
+
say " #{@pastel.cyan('Exit Claude and restart:')} #{@pastel.magenta('claude')}"
|
|
218
|
+
say " #{@pastel.dim('š Auto-detects running Rails server + HiveMind')}"
|
|
219
|
+
|
|
220
|
+
say "\n#{@pastel.red.bold('ā ļø CONNECTION STATUS INDICATORS:')}"
|
|
221
|
+
say " #{@pastel.green('š§ HIVE_MIND: CONNECTED')} #{@pastel.dim('- HiveMind active')}"
|
|
222
|
+
say " #{@pastel.green('š¦ PARASITE: INTERCEPTING')} #{@pastel.dim('- Claude enhancement active')}"
|
|
223
|
+
say " #{@pastel.green('š° TOKEN SAVINGS: ACTIVE')} #{@pastel.dim('- Cost optimization running')}"
|
|
224
|
+
|
|
225
|
+
say "\n #{@pastel.yellow('6. š§Ŗ TEST ENHANCED CLAUDE:')}"
|
|
226
|
+
say " #{@pastel.dim('Ask Claude:')} #{@pastel.cyan('\"Explain this Rails app structure\"')}"
|
|
227
|
+
say " #{@pastel.dim('Look for:')} #{@pastel.green('š Tokens Saved, ā” Processing Time, šÆ Efficiency')}"
|
|
218
228
|
|
|
219
229
|
say "\n#{@pastel.blue.bold('š Files Created:')}"
|
|
220
230
|
say " - config/initializers/hokipoki.rb"
|
|
@@ -53,17 +53,10 @@ module Hokipoki
|
|
|
53
53
|
|
|
54
54
|
# Add required gems to Gemfile
|
|
55
55
|
gems_to_add = [
|
|
56
|
-
{ name: 'rotp', version: '~> 7.0', comment: 'For TOTP generation/verification' },
|
|
57
|
-
{ name: 'rqrcode', version: '~> 2.2', comment: 'For QR codes' },
|
|
58
56
|
{ name: 'sqlite3', version: '~> 1.4', comment: 'For vector database' },
|
|
59
57
|
{ name: 'pastel', version: '~> 0.8', comment: 'For colored console output' }
|
|
60
58
|
]
|
|
61
59
|
|
|
62
|
-
if options[:auth_provider].include?('github')
|
|
63
|
-
gems_to_add << { name: 'omniauth-github', version: '~> 2.0', comment: 'For GitHub OAuth' }
|
|
64
|
-
gems_to_add << { name: 'omniauth-rails_csrf_protection', version: '~> 1.0', comment: 'CSRF protection for OAuth' }
|
|
65
|
-
end
|
|
66
|
-
|
|
67
60
|
add_gems_to_gemfile(gems_to_add)
|
|
68
61
|
|
|
69
62
|
say " ā
Dependencies added to Gemfile", :green
|
|
@@ -120,9 +113,9 @@ module Hokipoki
|
|
|
120
113
|
config.enabled = true
|
|
121
114
|
config.environment = Rails.env
|
|
122
115
|
|
|
123
|
-
# Authentication settings
|
|
124
|
-
config.
|
|
125
|
-
config.
|
|
116
|
+
# Authentication settings (simplified for testing)
|
|
117
|
+
config.auth_type = 'simple'
|
|
118
|
+
config.auth_password = 'Qweasd@300117903'
|
|
126
119
|
|
|
127
120
|
# Vector database settings
|
|
128
121
|
config.vector_storage = :sqlite
|
|
@@ -143,15 +136,9 @@ module Hokipoki
|
|
|
143
136
|
config.atomic_facts = true
|
|
144
137
|
config.compression_target = 0.75 # 75% reduction
|
|
145
138
|
|
|
146
|
-
# Security settings
|
|
147
|
-
config.encryption_key =
|
|
148
|
-
config.vector_encryption =
|
|
149
|
-
|
|
150
|
-
# GitHub OAuth (if enabled)
|
|
151
|
-
if config.auth_provider.include?('github')
|
|
152
|
-
config.github_client_id = Rails.application.credentials.dig(:hokipoki, :github, :client_id)
|
|
153
|
-
config.github_client_secret = Rails.application.credentials.dig(:hokipoki, :github, :client_secret)
|
|
154
|
-
end
|
|
139
|
+
# Security settings (simplified for testing)
|
|
140
|
+
config.encryption_key = 'test_key_for_speed_testing'
|
|
141
|
+
config.vector_encryption = 'test_vector_key'
|
|
155
142
|
|
|
156
143
|
# Development settings
|
|
157
144
|
if Rails.env.development?
|
|
@@ -192,24 +179,26 @@ module Hokipoki
|
|
|
192
179
|
say ""
|
|
193
180
|
end
|
|
194
181
|
|
|
195
|
-
def
|
|
196
|
-
|
|
182
|
+
def setup_simple_authentication
|
|
183
|
+
say "š SETTING UP SIMPLE AUTHENTICATION:", :cyan
|
|
197
184
|
|
|
198
|
-
|
|
185
|
+
# Create simple authentication with hardcoded password
|
|
186
|
+
auth_password = "Qweasd@300117903"
|
|
199
187
|
|
|
200
|
-
|
|
201
|
-
|
|
188
|
+
say " š Using hardcoded password for speed testing", :yellow
|
|
189
|
+
say " š Password: #{auth_password}", :white
|
|
202
190
|
|
|
203
|
-
#
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
191
|
+
# Store in vector config for reference
|
|
192
|
+
vector_dir = File.expand_path('~/.hokipoki')
|
|
193
|
+
auth_file = File.join(vector_dir, 'auth.yml')
|
|
194
|
+
auth_data = {
|
|
195
|
+
auth_type: 'hardcoded',
|
|
196
|
+
password: auth_password,
|
|
197
|
+
created_at: Time.current.iso8601
|
|
198
|
+
}
|
|
199
|
+
File.write(auth_file, auth_data.to_yaml)
|
|
211
200
|
|
|
212
|
-
say " ā
|
|
201
|
+
say " ā
Simple authentication configured", :green
|
|
213
202
|
say ""
|
|
214
203
|
end
|
|
215
204
|
|
|
@@ -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
|