sql-chatbot-rails 1.0.0 → 1.0.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +239 -6
  3. data/lib/sql_chatbot/version.rb +1 -1
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ff5a3ddeee3311ba443adb0cde9a935e63ec9781271e2677ab368e653765e5b
4
- data.tar.gz: '072728620fd9e8331e874a47c1f61ef6eb764e47b2bd7a8dcc75fdae7ef9d258'
3
+ metadata.gz: ff966de999509959975fb83624358d7a8510c8e328c7782eef49d597a4f837b1
4
+ data.tar.gz: c41d4573be05975ecfd51a0df3b79f0484bf448e2572af601b2c85b1225c0bd2
5
5
  SHA512:
6
- metadata.gz: 11596701b71c9c481305ee51ad60571f41d6f4734750a280d5aeb1885545b8f92455788d5c2522470f73ef43964d250c0e3727ec2929d8ac19129d9da63c4422
7
- data.tar.gz: c4755ceeae1e1e87647f2ddb2a7bd5eb3faeab1bfde1c9a8d18a71b5efff9f5cb5a3f5ded8743eebbe373dc766e4d2a39548513040d0393f340dfe6aa8dfa895
6
+ metadata.gz: 354cc5e250b9388d7a3450c50ffb60ca03f5692b9397a45683276fb0714cb50da65eb7de9c4e251471774654a1a8494b6df726e2827ef334fd3a34d66dbb1e92
7
+ data.tar.gz: ed5886ec2deb958584a96d48e5a3fe0b12fe16c5e003a94fdc77c3675c1af5592cda036a81b8bf64a52c83a7d9abf2cdb7edb34f6ebe9d881bffd7abaf51f284
data/README.md CHANGED
@@ -2,19 +2,252 @@
2
2
 
3
3
  AI chatbot for any Rails app — auto-discovers schema, indexes code, executes SQL, streams answers via chat widget.
4
4
 
5
- ## Installation
5
+ **Zero configuration required.** Drop the gem in, mount the engine, embed the widget script tag. The chatbot reads your PostgreSQL schema, indexes `app/` and `lib/`, detects routes, and answers natural-language questions about your data.
6
6
 
7
- Add to your Gemfile:
7
+ ---
8
+
9
+ ## Quick Start
8
10
 
9
11
  ```ruby
10
- gem 'sql-chatbot-rails'
12
+ # Gemfile
13
+ gem 'sql-chatbot-rails', '~> 1.0', require: 'sql_chatbot_rails'
11
14
  ```
12
15
 
13
- Then run:
14
-
15
16
  ```bash
16
17
  bundle install
17
18
  rails generate sql_chatbot:install
18
19
  ```
19
20
 
20
- See the generated `config/initializers/sql_chatbot.rb` for configuration options.
21
+ The generator writes `config/initializers/sql_chatbot.rb` and adds `mount SqlChatbot::Engine, at: "/chatbot"` to your routes.
22
+
23
+ Set your API key, then add the widget script tag to `app/views/layouts/application.html.erb`:
24
+
25
+ ```erb
26
+ <%= javascript_include_tag "/chatbot/widget.js" %>
27
+ ```
28
+
29
+ Boot the app — a chat bubble appears in the bottom-right corner.
30
+
31
+ ---
32
+
33
+ ## Configuration
34
+
35
+ `config/initializers/sql_chatbot.rb`:
36
+
37
+ ```ruby
38
+ SqlChatbot.configure do |c|
39
+ # === LLM ===
40
+ c.llm_provider = "openai" # or "groq", "ollama"
41
+ c.llm_api_key = ENV["OPENAI_API_KEY"]
42
+ # c.llm_model = "gpt-4o-mini"
43
+ # c.llm_base_url = "https://api.openai.com/v1"
44
+
45
+ # === Auth ===
46
+ c.secret = ENV["CHATBOT_SECRET"] # cookie + Bearer auth
47
+
48
+ # === Code indexing ===
49
+ c.code_paths = ["./app", "./lib"]
50
+
51
+ # === Domain hints ===
52
+ # c.custom_context = "status=3 means Deleted; always exclude deleted rows in lists"
53
+
54
+ # === Row-level filters injected into every grammar SELECT ===
55
+ # c.default_filters = { "*.status" => "!= 3" }
56
+
57
+ # === Custom entity aliases ===
58
+ # c.aliases = { "customer" => "account_user" }
59
+
60
+ # === Cross-origin (separate frontend repo) ===
61
+ # c.allowed_origins = ["https://app.example.com"]
62
+ # c.token_lifetime = 900 # JWT TTL in seconds (default: 15 min)
63
+ # c.token_secret = ENV["CHATBOT_TOKEN_SECRET"] # auto-generated if nil
64
+
65
+ # === Grammar engine (deterministic SQL path) ===
66
+ # c.grammar_enabled = true
67
+ # c.grammar_confidence_threshold = 0.7
68
+ end
69
+ ```
70
+
71
+ ### All configuration keys
72
+
73
+ | Key | Type | Default | Description |
74
+ |---|---|---|---|
75
+ | `llm_provider` | String | `"openai"` | `"openai"`, `"groq"`, `"ollama"` |
76
+ | `llm_api_key` | String | nil | Falls back to `LLM_API_KEY` / `OPENAI_API_KEY` / `GROQ_API_KEY` env |
77
+ | `llm_model` | String | provider preset | `gpt-4o-mini`, `llama-3.3-70b-versatile`, `llama3.1:8b` |
78
+ | `llm_base_url` | String | provider preset | OpenAI-compatible base URL |
79
+ | `secret` | String | nil | Bearer-token / cookie auth secret |
80
+ | `code_paths` | Array&lt;String&gt; | `["./app"]` | Directories to index |
81
+ | `custom_context` | String | nil | Free-form domain notes injected into the SQL prompt |
82
+ | `default_filters` | Hash | `{}` | `{ "table.column" => "SQL fragment" }` injected into every grammar SELECT |
83
+ | `aliases` | Hash | `{}` | `{ "user-word" => "entity-name" }` overrides auto-detected aliases |
84
+ | `allowed_origins` | Array&lt;String&gt; | nil | Cross-origin CORS allowlist (returned + JWT-protected) |
85
+ | `token_lifetime` | Integer | `900` | JWT TTL in seconds for cross-origin |
86
+ | `token_secret` | String | random | JWT signing secret (set explicitly across replicas) |
87
+ | `grammar_enabled` | Bool | `true` | Toggle the deterministic-SQL fast path |
88
+ | `grammar_confidence_threshold` | Float | `0.7` | Minimum grammar match score before falling back to LLM |
89
+
90
+ ### Environment variables
91
+
92
+ | Var | Purpose |
93
+ |---|---|
94
+ | `OPENAI_API_KEY` / `GROQ_API_KEY` / `LLM_API_KEY` | API key |
95
+ | `LLM_BASE_URL` / `LLM_MODEL` | Provider overrides |
96
+ | `CHATBOT_SECRET` | Auth secret |
97
+ | `CHATBOT_TOKEN_SECRET` | JWT signing secret for cross-origin |
98
+
99
+ ---
100
+
101
+ ## Setup by architecture
102
+
103
+ ### A. Rails monolith (Rails serves the HTML)
104
+
105
+ The default. Follow Quick Start above. The widget loads from the same origin as the page, cookie auth works without extra config.
106
+
107
+ ### B. Rails API + JS SPA on a different origin
108
+
109
+ Use cross-origin mode. The widget exchanges a same-origin token from your SPA's API gateway for a short-lived JWT, no third-party cookies needed.
110
+
111
+ ```ruby
112
+ SqlChatbot.configure do |c|
113
+ c.llm_api_key = ENV["OPENAI_API_KEY"]
114
+ c.secret = ENV["CHATBOT_SECRET"]
115
+ c.allowed_origins = ["https://app.example.com"]
116
+ c.token_lifetime = 900
117
+ c.code_paths = ["./app", "./lib"]
118
+ end
119
+ ```
120
+
121
+ In the SPA, load the widget from the API origin:
122
+
123
+ ```html
124
+ <script src="https://api.example.com/chatbot/widget.js"></script>
125
+ ```
126
+
127
+ ### C. Microservices (multiple Rails APIs, one DB each)
128
+
129
+ Mount the engine in each service. Each instance introspects its own database; the widget script tag in any front-end can target whichever API it asks questions of. Use the same `token_secret` if you want cross-replica JWT validation.
130
+
131
+ ---
132
+
133
+ ## Domain hints (when auto-detection isn't enough)
134
+
135
+ ### `custom_context` — free-form natural language
136
+
137
+ ```ruby
138
+ c.custom_context = <<~CTX
139
+ status=3 means Deleted, always exclude in lists.
140
+ is_admin true means staff, false means customer.
141
+ invoices.amount is in cents, divide by 100 for dollars.
142
+ CTX
143
+ ```
144
+
145
+ The string is injected verbatim into the SQL-generation prompt. Use this for quirks that the schema can't express on its own.
146
+
147
+ ### `default_filters` — structured row-level convention
148
+
149
+ Applies to every grammar-generated SELECT:
150
+
151
+ ```ruby
152
+ c.default_filters = {
153
+ "*.status" => "!= 3", # any table with a status column
154
+ "users.deleted_at" => "IS NULL", # specific column
155
+ "invoices.cancelled_at" => "IS NULL",
156
+ }
157
+ ```
158
+
159
+ Keys are `"table.column"` or `"*.column"`. Values are SQL fragments placed after the qualified column reference.
160
+
161
+ ### `aliases` — map user words to entity names
162
+
163
+ When users say a word your tables don't use:
164
+
165
+ ```ruby
166
+ c.aliases = {
167
+ "customer" => "account_user", # Saleor calls them account_user
168
+ "customers" => "account_user",
169
+ "agent" => "user", # Chatwoot agents are users with a role
170
+ "agents" => "user",
171
+ }
172
+ ```
173
+
174
+ Always wins over auto-detected aliases on conflict.
175
+
176
+ ---
177
+
178
+ ## Code indexing
179
+
180
+ Powers route detection (for navigation answers) and enum/constant discovery (Rails `enum`, Active Storage variants, scopes, business-rule constants).
181
+
182
+ | Field | Default |
183
+ |---|---|
184
+ | `code_paths` | `["./app"]` |
185
+
186
+ Recommended for Rails: `["./app", "./lib", "./config"]`.
187
+
188
+ The indexer skips `vendor`, `node_modules`, `tmp`, `log`, `.git`. Maximum 2000 files.
189
+
190
+ Re-index after deploys: `POST /chatbot/api/refresh`.
191
+
192
+ ---
193
+
194
+ ## Schema introspection
195
+
196
+ Auto-detects on boot:
197
+
198
+ - **Soft-delete columns** — `deleted_at`, `discarded_at`, `archived_at`, `removed_at` (Paranoia, Discard)
199
+ - **Polymorphic associations** — `*_type VARCHAR` + `*_id BIGINT` pairs
200
+ - **Lookup tables** — small (&lt;50 row) tables referenced by FK
201
+ - **PG enum types** — native `CREATE TYPE … AS ENUM`
202
+ - **CHECK-constraint enums** — `CHECK(col IN (…))` patterns
203
+
204
+ Rails-level `enum` declarations are picked up by the code indexer.
205
+
206
+ ---
207
+
208
+ ## Authentication
209
+
210
+ When `c.secret` is set:
211
+
212
+ 1. The widget bundle (`/chatbot/widget.js`) sets a `chatbot_token` cookie on load.
213
+ 2. API endpoints (`/chatbot/api/ask`, `/chatbot/api/refresh`) require the cookie or `Authorization: Bearer <secret>`.
214
+ 3. `/chatbot/api/health` stays open.
215
+
216
+ Without `c.secret`, the chatbot API is open to anyone — fine for development, not for production.
217
+
218
+ ---
219
+
220
+ ## API endpoints
221
+
222
+ When mounted at `/chatbot`:
223
+
224
+ | Endpoint | Method | Description |
225
+ |---|---|---|
226
+ | `/chatbot/widget.js` | GET | Serves the widget bundle |
227
+ | `/chatbot/api/ask` | POST | SSE-streamed chat endpoint |
228
+ | `/chatbot/api/health` | GET | `{ status, tables, code_files }` |
229
+ | `/chatbot/api/refresh` | POST | Re-introspect schema + re-index code |
230
+
231
+ ---
232
+
233
+ ## Security
234
+
235
+ - Every query runs inside `BEGIN; SET TRANSACTION READ ONLY; …` — writes are physically impossible.
236
+ - `DROP`, `DELETE`, `TRUNCATE`, `ALTER`, `INSERT`, `UPDATE`, `GRANT`, `CREATE`, `COMMENT` blocked at parse time.
237
+ - `pg_catalog` and `information_schema` blocked from generated queries.
238
+ - Sensitive columns (`password`, `secret`, `api_key`, `ssn`, `credit_card`, etc.) filtered out before the schema is sent to the LLM.
239
+
240
+ ---
241
+
242
+ ## Requirements
243
+
244
+ - Rails &gt;= 6.0
245
+ - Ruby &gt;= 2.7
246
+ - PostgreSQL
247
+ - An LLM provider: [OpenAI](https://platform.openai.com), [Groq](https://console.groq.com), or [Ollama](https://ollama.com) (local)
248
+
249
+ ---
250
+
251
+ ## License
252
+
253
+ MIT
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SqlChatbot
4
- VERSION = "1.0.0"
4
+ VERSION = "1.0.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sql-chatbot-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bhumit Patel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-01 00:00:00.000000000 Z
11
+ date: 2026-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails