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 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,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -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,4 @@
1
+ module Gromit
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -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
@@ -0,0 +1,6 @@
1
+ module Vapey
2
+ module Rails
3
+ module ApplicationHelper
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Vapey
2
+ module Rails
3
+ class ApplicationJob < ActiveJob::Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ module Vapey
2
+ module Rails
3
+ class ApplicationMailer < ActionMailer::Base
4
+ default from: "from@example.com"
5
+ layout "mailer"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Gromit
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Gromit</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "gromit/application", media: "all" %>
9
+ </head>
10
+ <body>
11
+
12
+ <%= yield %>
13
+
14
+ </body>
15
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,8 @@
1
+ Gromit::Engine.routes.draw do
2
+
3
+ scope '/', defaults: { format: :json } do
4
+ get '/healthcheck', to: 'gromit#healthcheck'
5
+ post '/search', to: 'gromit#search'
6
+ post '/upsert', to: 'gromit#upsert'
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ %w[
2
+ markdown_parser
3
+ reindexer
4
+ uploader
5
+ ].each { |name| require_relative name }
@@ -0,0 +1,12 @@
1
+ require "rails"
2
+
3
+ module Gromit
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace Gromit
6
+
7
+ rake_tasks do
8
+ path = File.expand_path(__dir__)
9
+ Dir.glob("#{path}/tasks/**/*.rake").each { |f| load f }
10
+ end
11
+ end
12
+ end
@@ -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,6 @@
1
+ namespace :gromit do
2
+ desc "Reindex"
3
+ task :reindex do
4
+ # Task goes here
5
+ end
6
+ 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
@@ -0,0 +1,3 @@
1
+ module Gromit
2
+ VERSION = "0.1.0"
3
+ 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
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :gromit do
3
+ # # Task goes here
4
+ # 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: []