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.
- checksums.yaml +4 -4
- data/README.md +239 -6
- data/lib/sql_chatbot/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ff966de999509959975fb83624358d7a8510c8e328c7782eef49d597a4f837b1
|
|
4
|
+
data.tar.gz: c41d4573be05975ecfd51a0df3b79f0484bf448e2572af601b2c85b1225c0bd2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
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
|
-
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
8
10
|
|
|
9
11
|
```ruby
|
|
10
|
-
|
|
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
|
-
|
|
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<String> | `["./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<String> | 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 (<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 >= 6.0
|
|
245
|
+
- Ruby >= 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
|
data/lib/sql_chatbot/version.rb
CHANGED
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.
|
|
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-
|
|
11
|
+
date: 2026-05-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|