gromit 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +8 -0
- data/app/assets/config/gromit_manifest.js +1 -0
- data/app/assets/stylesheets/gromit/application.css +15 -0
- data/app/controllers/gromit/application_controller.rb +4 -0
- data/app/controllers/gromit/gromit_controller.rb +52 -0
- data/app/helpers/gromit/application_helper.rb +6 -0
- data/app/jobs/gromit/application_job.rb +6 -0
- data/app/mailers/gromit/application_mailer.rb +8 -0
- data/app/models/gromit/application_record.rb +5 -0
- data/app/views/layouts/gromit/application.html.erb +15 -0
- data/config/routes.rb +8 -0
- data/lib/gromit/core.rb +5 -0
- data/lib/gromit/engine.rb +12 -0
- data/lib/gromit/markdown_parser.rb +147 -0
- data/lib/gromit/reindexer.rb +72 -0
- data/lib/gromit/tasks/gromit.rake +6 -0
- data/lib/gromit/uploader.rb +46 -0
- data/lib/gromit/version.rb +3 -0
- data/lib/gromit.rb +53 -0
- data/lib/tasks/gromit_tasks.rake +4 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 00dc903e9068922d891b726629b7e5e3ce058c2f073766775f1879fe2c5f20f9
|
4
|
+
data.tar.gz: 04e16aedf5357dfee62a94090c60c292af3fa5beba3e98d6066f1c119dec4d09
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dad20891a96a6589f59feb912b40eb99fc57dfe8adac93e9477a40af4386b5d7a8acf796365dffa31410afd3fe7a3f8a0ec2df5252590ca409ca83a46c318e1e
|
7
|
+
data.tar.gz: a60f72ed8958c7627bce422c713c30351682ba15dcd620ba1fddb6a65af27cecd76a5367787eed8cc9d6b1933425ef723669687c43dd7dbe5a50023b0fc3dba2
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2023 David Giffin
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Gromit
|
2
|
+
Short description and motivation.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
How to use my plugin.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem "gromit"
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install gromit
|
22
|
+
```
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
Contribution directions go here.
|
26
|
+
|
27
|
+
## License
|
28
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
//= link_directory ../stylesheets/gromit.css
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Gromit
|
2
|
+
class GromitController < ApplicationController
|
3
|
+
|
4
|
+
def healthcheck
|
5
|
+
gromit = Gromit::Search.new
|
6
|
+
|
7
|
+
begin
|
8
|
+
# Send a PING command to Redis
|
9
|
+
redis_ping_response = gromit.redis.ping
|
10
|
+
|
11
|
+
# Check if the Redis server responded with "PONG"
|
12
|
+
if redis_ping_response == 'PONG'
|
13
|
+
|
14
|
+
# create the index if it's not already there
|
15
|
+
gromit.create_index
|
16
|
+
else
|
17
|
+
render json: { status: 'unhealthy', message: 'Redis connection is unhealthy' }
|
18
|
+
end
|
19
|
+
rescue Redis::CommandError, Redis::CannotConnectError => e
|
20
|
+
if e.message == "Index already exists"
|
21
|
+
render json: { status: 'healthy', message: 'Redis connection is healthy' }
|
22
|
+
else
|
23
|
+
render json: { status: 'unhealthy', message: "Redis connection error: #{e.message}" }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def search
|
29
|
+
gromit = Gromit::Search.new
|
30
|
+
result = gromit.find_by_embedding(params[:embedding])
|
31
|
+
render json: result
|
32
|
+
end
|
33
|
+
|
34
|
+
def upsert
|
35
|
+
gromit = Gromit::Search.new
|
36
|
+
|
37
|
+
# Hopefully don't have to do this
|
38
|
+
## json_params = JSON.parse(request.raw_post)
|
39
|
+
|
40
|
+
# Extract the key and value from the request data
|
41
|
+
id = params[:id]
|
42
|
+
|
43
|
+
# Upsert the record into the Redis database
|
44
|
+
gromit.redis.json_set("item:#{id}", Rejson::Path.root_path, params.deep_stringify_keys)
|
45
|
+
|
46
|
+
# Return a success response
|
47
|
+
render json: { status: 'success', message: "Record upserted successfully", key: "item:#{id}" }
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
data/config/routes.rb
ADDED
data/lib/gromit/core.rb
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
|
2
|
+
class Gromit::MarkdownParser
|
3
|
+
attr_reader :sections
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def redis
|
8
|
+
@@redis ||= Redis.new(host: ENV.fetch("REDIS_HOST") { "127.0.0.1" }, port: ENV.fetch("REDIS_PORT") { "6379" }.to_i)
|
9
|
+
end
|
10
|
+
|
11
|
+
def openai
|
12
|
+
@@openai ||= OpenAI::Client.new(access_token: ENV.fetch("OPENAPI_ACCESS_TOKEN"))
|
13
|
+
end
|
14
|
+
|
15
|
+
def process(directory)
|
16
|
+
|
17
|
+
git_file_list(directory).map do |file|
|
18
|
+
file_path = File.expand_path(File.join(directory, file))
|
19
|
+
|
20
|
+
next unless file.match(/\.md$/)
|
21
|
+
|
22
|
+
puts "processing file: #{file_path}"
|
23
|
+
|
24
|
+
page_id = Digest::SHA1.hexdigest(file_path)
|
25
|
+
title = File.read(file_path).lines.first.strip.gsub(/^#\s+/,'')
|
26
|
+
checksum = Digest::MD5.hexdigest(File.read(file_path))
|
27
|
+
|
28
|
+
parser = Gromit::MarkdownParser.new(file_path)
|
29
|
+
sections = parser.sections.map do |section|
|
30
|
+
section = process_markdown(section)
|
31
|
+
section_title = section.lines.first.strip.gsub(/^i[#]+\s+/,'')
|
32
|
+
section_id = Digest::MD5.hexdigest(section)
|
33
|
+
id = Digest::MD5.hexdigest("#{page_id}:#{section_id}")
|
34
|
+
|
35
|
+
# get cached embedding or call out to openai
|
36
|
+
token_count, embedding = get_embedding(section, section_id)
|
37
|
+
|
38
|
+
{
|
39
|
+
id: id,
|
40
|
+
page_id: page_id,
|
41
|
+
section_id: section_id,
|
42
|
+
file: file,
|
43
|
+
title: title,
|
44
|
+
section_title: section_title,
|
45
|
+
content: section,
|
46
|
+
checksum: checksum,
|
47
|
+
token_count: token_count,
|
48
|
+
embedding: embedding,
|
49
|
+
}
|
50
|
+
|
51
|
+
end
|
52
|
+
end.compact.flatten
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_embedding(section, section_id)
|
56
|
+
token_count = nil
|
57
|
+
embedding = nil
|
58
|
+
data = redis.get(section_id)
|
59
|
+
|
60
|
+
if data.nil?
|
61
|
+
|
62
|
+
# OpenAI recommends replacing newlines with spaces for best results (specific to embeddings)
|
63
|
+
input = section.gsub(/\n/m, ' ')
|
64
|
+
response = openai.embeddings(parameters: { input: input, model: "text-embedding-ada-002"})
|
65
|
+
|
66
|
+
token_count = response['usage']['total_tokens']
|
67
|
+
embedding = response['data'].first['embedding']
|
68
|
+
|
69
|
+
redis.set(section_id, {'token_count' => token_count, 'embedding' => embedding}.to_json)
|
70
|
+
else
|
71
|
+
cached_embedding = JSON.parse(data)
|
72
|
+
token_count = cached_embedding['token_count']
|
73
|
+
embedding = cached_embedding['embedding']
|
74
|
+
end
|
75
|
+
[token_count, embedding]
|
76
|
+
end
|
77
|
+
|
78
|
+
def git_file_list(dir)
|
79
|
+
`cd #{dir} && git ls-files`.split("\n")
|
80
|
+
end
|
81
|
+
|
82
|
+
def process_markdown(file)
|
83
|
+
mkdocs_url = "https://docs-mkdocs.releaseapp.io"
|
84
|
+
|
85
|
+
# handle images
|
86
|
+
# TODO: deal with spaces??
|
87
|
+
file.gsub!(/(!\[[^\]]*?\])([\(<]+)[\.\/]+\.gitbook\/assets\/(.*?)([\)>]+)/m) do
|
88
|
+
"#{$1}#{$2}#{mkdocs_url}/img/#{$3}#{$4}"
|
89
|
+
end
|
90
|
+
|
91
|
+
# remove the .md extension from the end of the URLs from gitbook
|
92
|
+
file.gsub!(/(\[[^\]]+?\])\((.*?)\.md([#a-z0-9]*)\)/) do |match|
|
93
|
+
"#{$1}(#{$2}#{$3})"
|
94
|
+
end
|
95
|
+
|
96
|
+
# handle "mentions"
|
97
|
+
file.gsub!(/\[([^\]]+?).md\]\((.*?)\.md([#a-z0-9]*) "mention"\)/) do |match|
|
98
|
+
link = "#{$2}#{$3}"
|
99
|
+
title = $1.gsub("-", ' ').titleize
|
100
|
+
"[#{title}](#{link})"
|
101
|
+
end
|
102
|
+
|
103
|
+
# convert gitbook hints to admonitions
|
104
|
+
# multi-line shortest match ...
|
105
|
+
file.gsub!(/{%\s+hint style="(.*?)"\s+?%}(.*?){% endhint %}/m) do |match|
|
106
|
+
ret = "!!! #{$1}\n"
|
107
|
+
ret += $2.lines.map{|line| " #{line}" }.join()
|
108
|
+
ret
|
109
|
+
end
|
110
|
+
|
111
|
+
file
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
def initialize(file_path)
|
117
|
+
@file_path = file_path
|
118
|
+
@sections = []
|
119
|
+
parse_file
|
120
|
+
end
|
121
|
+
|
122
|
+
def parse_file
|
123
|
+
current_section = []
|
124
|
+
File.read(@file_path).lines do |line|
|
125
|
+
# Check if the line is a header (starts with one or more '#' characters)
|
126
|
+
if header?(line)
|
127
|
+
# Save the previous section if it's not empty
|
128
|
+
@sections << current_section.join unless current_section.empty?
|
129
|
+
# Start a new section
|
130
|
+
current_section = [line]
|
131
|
+
else
|
132
|
+
# Add the line to the current section
|
133
|
+
current_section << line
|
134
|
+
end
|
135
|
+
end
|
136
|
+
# Save the last section if it's not empty
|
137
|
+
@sections << current_section.join unless current_section.empty?
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
# Check if a line is a Markdown header
|
143
|
+
def header?(line)
|
144
|
+
line.strip.start_with?('#')
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'openai'
|
3
|
+
require 'dotenv'
|
4
|
+
require 'optparse'
|
5
|
+
require 'redis'
|
6
|
+
require 'rejson'
|
7
|
+
require 'active_support/all'
|
8
|
+
|
9
|
+
require_relative 'markdown_parser'
|
10
|
+
|
11
|
+
Dotenv.load
|
12
|
+
|
13
|
+
|
14
|
+
class Gromit::Reindexer
|
15
|
+
attr_accessor :redis
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def invoke
|
19
|
+
options = { drop: false }
|
20
|
+
OptionParser.new do |opts|
|
21
|
+
opts.banner = "Usage: reindexer.rb [options]"
|
22
|
+
|
23
|
+
opts.on('-s', '--source SOURCE_DIR', 'Source directory') do |source_dir|
|
24
|
+
options[:source_dir] = source_dir
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on('-d', '--drop', 'Drop and create index before reindexing') do
|
28
|
+
options[:drop] = true
|
29
|
+
end
|
30
|
+
|
31
|
+
end.parse!
|
32
|
+
|
33
|
+
# Validate the presence of source and destination directories
|
34
|
+
unless options[:source_dir]
|
35
|
+
puts "Error: source directory (-s or --source) must be specified."
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
# Instantiate the ToMkDocs class and perform the conversion
|
40
|
+
reindexer = Gromit::Reindexer.new
|
41
|
+
reindexer.run(options[:source_dir], drop: options[:drop])
|
42
|
+
|
43
|
+
puts "Reindexer completed successfully."
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@redis ||= Redis.new(host: ENV.fetch("REDIS_HOST") { "127.0.0.1" }, port: ENV.fetch("REDIS_PORT") { "6379" }.to_i)
|
49
|
+
end
|
50
|
+
|
51
|
+
def run(directory = nil, drop: false)
|
52
|
+
gromit = Gromit::Search.new
|
53
|
+
|
54
|
+
if drop
|
55
|
+
gromit.recreate_index
|
56
|
+
end
|
57
|
+
|
58
|
+
directory ||= ENV.fetch("DOCS_DIRECTORY") { "/Users/david/development/docs/examples" }
|
59
|
+
sections = Gromit::MarkdownParser.process(directory)
|
60
|
+
sections.each do |section|
|
61
|
+
puts "indexing: #{section[:file]} section: #{section[:section_title]}"
|
62
|
+
data = section.stringify_keys
|
63
|
+
id = data['id']
|
64
|
+
gromit.redis.json_set("item:#{id}", Rejson::Path.root_path, data)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
if __FILE__ == $0
|
71
|
+
Gromit::Reindexer::invoke
|
72
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'openai'
|
3
|
+
require 'httparty'
|
4
|
+
require 'dotenv'
|
5
|
+
require 'pathname'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
require_relative 'markdown_parser'
|
9
|
+
|
10
|
+
Dotenv.load
|
11
|
+
|
12
|
+
|
13
|
+
class Gromit::Uploader
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def invoke
|
17
|
+
options = {}
|
18
|
+
|
19
|
+
OptionParser.new do |opts|
|
20
|
+
opts.banner = "Usage: uploader.rb [options]"
|
21
|
+
|
22
|
+
opts.on('-s', '--source SOURCE_DIR', 'Source directory') do |source_dir|
|
23
|
+
options[:source_dir] = source_dir
|
24
|
+
end
|
25
|
+
end.parse!
|
26
|
+
|
27
|
+
path = Pathname.new(options.fetch(:source_dir, ''))
|
28
|
+
unless path.exist?
|
29
|
+
puts "Error: The source directory (-s or --source) doesn't exist or is not specified."
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
|
33
|
+
sections = Gromit::MarkdownParser.process(path.to_s)
|
34
|
+
sections.each do |section|
|
35
|
+
puts "uploading: #{section[:file]} section: #{section[:section_title]}"
|
36
|
+
Uploader::Partay.post('/upsert', { headers: {"Content-Type": "application/json"}, body: section.to_json })
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Partay
|
42
|
+
include HTTParty
|
43
|
+
base_uri ENV.fetch("BASE_URL") { "127.0.0.1:9292" }
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
data/lib/gromit.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require "gromit/version"
|
2
|
+
require "gromit/engine"
|
3
|
+
|
4
|
+
module Gromit
|
5
|
+
class Search
|
6
|
+
|
7
|
+
def find_by_embedding(embedding)
|
8
|
+
results = redis.call([
|
9
|
+
"FT.SEARCH", "index", "@embedding:[VECTOR_RANGE $r $BLOB]=>{$YIELD_DISTANCE_AS: my_scores}",
|
10
|
+
"PARAMS", "4", "BLOB", embedding.pack("E*"), "r", "5",
|
11
|
+
"LIMIT", "0", "10", "SORTBY", "my_scores", "DIALECT", "2"
|
12
|
+
])
|
13
|
+
count = results[0]
|
14
|
+
|
15
|
+
output = []
|
16
|
+
results[1..].each_slice(2) do |key,value|
|
17
|
+
data = JSON.parse(value[3])
|
18
|
+
result = { key: key }.merge(data)
|
19
|
+
result.delete("embedding")
|
20
|
+
output << result
|
21
|
+
end
|
22
|
+
|
23
|
+
output
|
24
|
+
end
|
25
|
+
|
26
|
+
def recreate_index
|
27
|
+
redis.call(["FT.DROP", "index"])
|
28
|
+
create_index
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_index
|
32
|
+
schema = {
|
33
|
+
id: "TAG",
|
34
|
+
page_id: "TAG",
|
35
|
+
section_id: "TAG",
|
36
|
+
file: "TEXT",
|
37
|
+
title: "TEXT",
|
38
|
+
content: "TEXT",
|
39
|
+
checksum: "TEXT",
|
40
|
+
token_count: "NUMERIC",
|
41
|
+
embedding: "VECTOR FLAT 6 DIM 1536 DISTANCE_METRIC COSINE TYPE FLOAT64",
|
42
|
+
}
|
43
|
+
preamble = "FT.CREATE index ON JSON PREFIX 1 item: SCHEMA "
|
44
|
+
command = (preamble + schema.map{|name,type| "$.#{name} AS #{name} #{type}"}.join(" ")).split(" ")
|
45
|
+
redis.call(command)
|
46
|
+
end
|
47
|
+
|
48
|
+
def redis
|
49
|
+
@redis ||= Redis.new(host: ENV.fetch("REDIS_HOST") { "127.0.0.1" }, port: ENV.fetch("REDIS_PORT") { "6379" }.to_i)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gromit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Giffin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-05-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: dotenv
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: httparty
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 7.0.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 7.0.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: redis
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rejson-rb
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.0.1
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.0.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: ruby-openai
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: gromit uses Redis and OpenAI embeddings to index your documentation
|
98
|
+
email:
|
99
|
+
- david@giffin.org
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- MIT-LICENSE
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- app/assets/config/gromit_manifest.js
|
108
|
+
- app/assets/stylesheets/gromit/application.css
|
109
|
+
- app/controllers/gromit/application_controller.rb
|
110
|
+
- app/controllers/gromit/gromit_controller.rb
|
111
|
+
- app/helpers/gromit/application_helper.rb
|
112
|
+
- app/jobs/gromit/application_job.rb
|
113
|
+
- app/mailers/gromit/application_mailer.rb
|
114
|
+
- app/models/gromit/application_record.rb
|
115
|
+
- app/views/layouts/gromit/application.html.erb
|
116
|
+
- config/routes.rb
|
117
|
+
- lib/gromit.rb
|
118
|
+
- lib/gromit/core.rb
|
119
|
+
- lib/gromit/engine.rb
|
120
|
+
- lib/gromit/markdown_parser.rb
|
121
|
+
- lib/gromit/reindexer.rb
|
122
|
+
- lib/gromit/tasks/gromit.rake
|
123
|
+
- lib/gromit/uploader.rb
|
124
|
+
- lib/gromit/version.rb
|
125
|
+
- lib/tasks/gromit_tasks.rake
|
126
|
+
homepage: https://github.com/releasehub-com/gromit
|
127
|
+
licenses:
|
128
|
+
- MIT
|
129
|
+
metadata:
|
130
|
+
homepage_uri: https://github.com/releasehub-com/gromit
|
131
|
+
source_code_uri: https://github.com/releasehub-com/gromit
|
132
|
+
changelog_uri: https://github.com/releasehub-com/gromit
|
133
|
+
post_install_message:
|
134
|
+
rdoc_options: []
|
135
|
+
require_paths:
|
136
|
+
- lib
|
137
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '3.0'
|
142
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
requirements: []
|
148
|
+
rubygems_version: 3.2.32
|
149
|
+
signing_key:
|
150
|
+
specification_version: 4
|
151
|
+
summary: 'gromit: vector search and indexing of your documentation'
|
152
|
+
test_files: []
|