asktive_record 0.1.0 → 0.1.4
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 +94 -65
- data/lib/asktive_record/version.rb +1 -1
- metadata +11 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06cd09084c657a6e24c587a1e19fff6ac6325bbb8d0f96eac05fca3fa7c26873
|
4
|
+
data.tar.gz: 5223d7f782965e07fc635cd32911f34571a9da511c4b8473441f11623681b998
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d95e9df03b249f4bc6b7d9b0020ea709e66f1b09b75fcfdb11a097157f4284c446dfc6d8c9adfbe246637a2a79740095052a64f60e16aad209837d4a12210efe
|
7
|
+
data.tar.gz: ae81db4d959bfd54ab3d53c7eff851269aae93fa3955e1acfdd1a7653667056d67803f00cda10b1d00702bb17e550640ede456ce6d2bf0fe37dc7f0d93e740fe
|
data/README.md
CHANGED
@@ -1,16 +1,17 @@
|
|
1
|
-
# AsktiveRecord:
|
1
|
+
# AsktiveRecord: A Ruby gem that lets your data answer like a human
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/asktive_record) <!-- Placeholder: Update once published -->
|
4
4
|
[](https://github.com/rpossan/asktive_record/actions/workflows/main.yml) <!-- Placeholder: Update with correct repo path -->
|
5
5
|
|
6
|
-
**AsktiveRecord** is a Ruby gem designed to bridge the gap between human language and database queries. It
|
7
|
-
|
8
|
-
Imagine your users (or even you, the developer!) asking questions like "*Show me the last five users who signed up*" or "*Which products had the most sales last month?*" and getting back the actual data, powered by an LLM translating these questions into SQL.
|
6
|
+
> **AsktiveRecord** is a Ruby gem designed to bridge the gap between human language and database queries. It lets you interact with your Rails database as if you were having a conversation with a knowledgeable assistant. Instead of writing SQL or chaining ActiveRecord methods, you simply ask questions in plain English—like (or any language) "Who are my newest users?" or "What products sold the most last month?"—and get clear, human-friendly answers. AsktiveRecord translates your questions into database queries behind the scenes, so you can focus on what you want to know, not how to write the query.
|
9
7
|
|
10
8
|
## Features
|
11
9
|
|
12
10
|
* **Natural Language to SQL**: Convert human-readable questions into SQL queries.
|
13
11
|
* **LLM Integration**: Currently supports OpenAI's ChatGPT, with a design that allows for future expansion to other LLMs (e.g., Gemini).
|
12
|
+
* **Get Answers, Not Just Data**: Use the `.answer` method to get concise, human-readable responses to your queries, rather than raw data or SQL.
|
13
|
+
* **Avoid ActiveRecord Chaining and SQL**: No need to write complex ActiveRecord queries or SQL statements. Just ask your question in natural language.
|
14
|
+
* **Works with Multiple Languages**: While the gem is designed with English in mind, it can handle queries in other languages, depending on the LLM's capabilities.
|
14
15
|
* **Flexible Querying Options**:
|
15
16
|
* Use with specific models (e.g., `User.ask("query")`)
|
16
17
|
* Use with service classes to query any table (e.g., `AskService.ask("query")`)
|
@@ -58,8 +59,6 @@ After installing the gem, you need to run the installer to generate the configur
|
|
58
59
|
|
59
60
|
```bash
|
60
61
|
$ bundle exec rails generate asktive_record:install
|
61
|
-
# or, if you're not in a full Rails app context for the generator (less common for this gem):
|
62
|
-
# $ bundle exec asktive_record:install (This might require further setup for standalone use)
|
63
62
|
```
|
64
63
|
|
65
64
|
This will create an initializer file at `config/initializers/asktive_record.rb`.
|
@@ -110,10 +109,20 @@ Run the setup command to help AsktiveRecord understand your database structure.
|
|
110
109
|
|
111
110
|
```bash
|
112
111
|
$ bundle exec rails generate asktive_record:setup
|
113
|
-
# or
|
114
|
-
# $ bundle exec asktive_record:setup
|
115
112
|
```
|
116
113
|
|
114
|
+
If your app uses a custom schema file or a non-standard schema location, you can specify the path in your configuration. For example, if your schema is located at `db/custom_schema.rb`, update your initializer:
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
AsktiveRecord.configure do |config|
|
118
|
+
config.db_schema_path = "db/custom_schema.rb"
|
119
|
+
config.skip_dump_schema = true # If your app uses a legacy schema or doesn't need to dump it using rails db:schema:dump (default is false)
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
This ensures AsktiveRecord reads the correct schema file when providing context to the LLM. Make sure the specified file accurately reflects your database structure.
|
124
|
+
|
125
|
+
|
117
126
|
This step ensures that the LLM has the necessary context about your tables and columns to generate accurate SQL queries. The schema content is passed with each query to the LLM in the current version.
|
118
127
|
|
119
128
|
## Usage
|
@@ -123,25 +132,32 @@ AsktiveRecord offers two ways to query your database using natural language:
|
|
123
132
|
### 1. Model-Specific Querying
|
124
133
|
|
125
134
|
This approach ties queries to specific models, ideal when you know which table you want to query.
|
135
|
+
If you want to apply AsktiveRecord for all your Rails models, add the `include AsktiveRecord` line in your `ApplicationRecord` or specific models. This allows you to use the `.ask` method directly on those models.
|
126
136
|
|
127
137
|
```ruby
|
128
138
|
# First, include AsktiveRecord in your ApplicationRecord or specific models
|
129
139
|
class ApplicationRecord < ActiveRecord::Base
|
130
140
|
primary_abstract_class
|
131
|
-
|
132
|
-
# include AsktiveRecord
|
141
|
+
include AsktiveRecord
|
133
142
|
end
|
134
143
|
|
135
|
-
#
|
144
|
+
# Or in a specific model
|
145
|
+
# In this case, you can query the User model directly for the model table. All queries will be scoped to the users table.
|
136
146
|
class User < ApplicationRecord
|
137
|
-
include AsktiveRecord
|
138
|
-
asktive_record # Activate model-specific setup (optional, future use)
|
147
|
+
include AsktiveRecord
|
139
148
|
end
|
140
149
|
|
141
150
|
# Now you can query the User model directly
|
142
|
-
|
143
|
-
|
144
|
-
|
151
|
+
query = User.ask("Show me the last five users who signed up")
|
152
|
+
# => Returns a Query object with SQL targeting the users table, not the sql executed yet
|
153
|
+
|
154
|
+
# Call the execute method to run the query on the database
|
155
|
+
results = query.execute
|
156
|
+
# => Returns an array of User objects (if the query is a SELECT) or raises an
|
157
|
+
|
158
|
+
# If you want to execute the query and get the response like human use the method answer
|
159
|
+
results = query.answer
|
160
|
+
# => Returns a string with the answer to the question, e.g., "The last five users who signed up are: [User1, User2, User3, User4, User5]"
|
145
161
|
```
|
146
162
|
|
147
163
|
### 2. Service-Class Querying (Any Table)
|
@@ -156,74 +172,62 @@ class AskService
|
|
156
172
|
end
|
157
173
|
|
158
174
|
# Now you can query any table through this service
|
159
|
-
|
160
|
-
|
161
|
-
# => Returns a Query object with SQL targeting the users table
|
175
|
+
asktive_record_query = AskService.ask("Which is the last user created?")
|
176
|
+
# => Returns a Query object with SQL targeting the users table, not the sql executed yet
|
162
177
|
|
163
|
-
|
164
|
-
|
165
|
-
# => Returns a Query object with SQL targeting the products table
|
178
|
+
asktive_record_query = AskService.ask("Which is the cheapest product?").execute
|
179
|
+
# => Returns an ActiveRecord::Result object (array of hashes) with the cheapest product details
|
166
180
|
|
167
|
-
|
168
|
-
asktive_record_query = AskService.ask(natural_query)
|
181
|
+
asktive_record_query = AskService.ask("Show me products with their categories").answer
|
169
182
|
# => Returns a Query object with SQL that might include JOINs between products and categories
|
183
|
+
# => Returns a string with the answer to the question, e.g., "The products with their categories are: [Product1, Product2, ...]"
|
170
184
|
```
|
171
185
|
|
172
|
-
|
186
|
+
### Working with Query Results
|
173
187
|
|
188
|
+
Once you have executed a query, you can work with the results. The `execute` method returns different types of results based on the context:
|
189
|
+
* If the query is from a model (e.g., `User.ask(...)`), it returns an array of model instances (e.g., `User` objects).
|
190
|
+
* If the query is from a service class (e.g., `AskService.ask(...)`), it returns an `ActiveRecord::Result` object, which is an array of hashes representing the query results.
|
174
191
|
```ruby
|
175
|
-
|
176
|
-
|
192
|
+
# Example of working with results from a model query
|
193
|
+
query = User.ask("Who are my newest users?")
|
194
|
+
results = query.execute
|
195
|
+
# => results is an array of User objects
|
177
196
|
```
|
178
197
|
|
179
|
-
###
|
198
|
+
### The `AsktiveRecord::Query` Object
|
199
|
+
|
200
|
+
### The `.answer` Method
|
201
|
+
|
202
|
+
The `.answer` method provides a human-friendly, natural language response to your query, instead of returning raw data or SQL. When you call `.answer` on a query object, AsktiveRecord executes the query and uses the LLM to generate a concise, readable answer based on the results.
|
203
|
+
|
204
|
+
### Example Usage
|
180
205
|
|
181
|
-
Regardless of which approach you use, you'll get a `AsktiveRecord::Query` object that you can work with:
|
182
206
|
|
183
207
|
```ruby
|
184
|
-
#
|
185
|
-
|
186
|
-
# =>
|
187
|
-
|
188
|
-
# 2. (Recommended) Sanitize the query
|
189
|
-
begin
|
190
|
-
asktive_record_query.sanitize! # Raises AsktiveRecord::SanitizationError if it's not a SELECT query by default
|
191
|
-
puts "Sanitized SQL: #{asktive_record_query.sanitized_sql}"
|
192
|
-
rescue AsktiveRecord::SanitizationError => e
|
193
|
-
puts "Error: #{e.message}"
|
194
|
-
# Handle error, maybe log it or don't execute the query
|
195
|
-
return
|
196
|
-
end
|
208
|
+
# Using a service class to ask a question
|
209
|
+
response = AskService.ask("Which is the cheapest product?").answer
|
210
|
+
# => "The cheapest product is the Earphone."
|
197
211
|
|
198
|
-
#
|
199
|
-
|
200
|
-
|
201
|
-
# Process the results
|
202
|
-
# - If executed via a model (e.g., User.ask), results will be an array of User objects.
|
203
|
-
# - If executed via a service class (e.g., AskService.ask), results will be an array of Hashes (from ActiveRecord::Result).
|
204
|
-
results.each do |record|
|
205
|
-
puts record.inspect
|
206
|
-
end
|
207
|
-
rescue AsktiveRecord::QueryExecutionError => e
|
208
|
-
puts "Error executing query: #{e.message}"
|
209
|
-
# Handle database execution errors
|
210
|
-
end
|
211
|
-
```
|
212
|
+
# Using a model to ask a question
|
213
|
+
response = User.ask("Who signed up most recently?").answer
|
214
|
+
# => "The most recently signed up user is Alice Smith."
|
212
215
|
|
213
|
-
|
216
|
+
# Asking for a summary
|
217
|
+
response = AskService.ask("How many orders were placed last week?").answer
|
218
|
+
# => "There were 42 orders placed last week."
|
219
|
+
```
|
214
220
|
|
215
|
-
|
221
|
+
Tip: You can get the query param and interpolates it into the ask method to get a more specific answer. For example, if you want to know the last user created, you can do:
|
216
222
|
|
217
223
|
```ruby
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
# Specify a target table name for the LLM prompt
|
223
|
-
asktive_record_query = AskService.ask("Show me all items on sale", table_name: "products")
|
224
|
+
customer = Customer.find(params[:id])
|
225
|
+
query = "Which is my most sold product?"
|
226
|
+
response = AskService.ask("For the customer #{customer.id}, #{query}").answer
|
227
|
+
# => "The most sold product for customer ABC is the Premium Widget."
|
224
228
|
```
|
225
229
|
|
226
|
-
|
230
|
+
The `.answer` method is ideal when you want a direct, human-readable summary, rather than an array of records or a SQL query.
|
227
231
|
|
228
232
|
The `ask()` method returns an instance of `AsktiveRecord::Query`. This object has a few useful methods:
|
229
233
|
|
@@ -235,6 +239,31 @@ The `ask()` method returns an instance of `AsktiveRecord::Query`. This object ha
|
|
235
239
|
* If the query originated from a service class (e.g., `AskService.ask(...)`), it uses `ActiveRecord::Base.connection.select_all` (for SELECT) or `execute` and returns an `ActiveRecord::Result` object (array of hashes) or connection-specific results.
|
236
240
|
* `to_s`: Returns the `sanitized_sql` (or `raw_sql` if `sanitized_sql` hasn't been modified from raw).
|
237
241
|
|
242
|
+
## Logging
|
243
|
+
AsktiveRecord provides logging to help you debug and monitor natural language queries, generated SQL, and results. By default, logs are sent to the Rails logger at the `:info` level.
|
244
|
+
|
245
|
+
### Example Log Output
|
246
|
+
|
247
|
+
When you run a query, you might see logs like:
|
248
|
+
|
249
|
+
```
|
250
|
+
[AsktiveRecord] Received question: "Who are my newest users?"
|
251
|
+
[AsktiveRecord] Generated SQL: SELECT * FROM users ORDER BY created_at DESC LIMIT 5;
|
252
|
+
[AsktiveRecord] Sanitized SQL: SELECT * FROM users ORDER BY created_at DESC LIMIT 5;
|
253
|
+
[AsktiveRecord] Executing SQL via User.find_by_sql
|
254
|
+
[AsktiveRecord] Query results: [#<User id: 1, name: "Alice", ...>, ...]
|
255
|
+
```
|
256
|
+
|
257
|
+
When using the `.answer` method:
|
258
|
+
|
259
|
+
```
|
260
|
+
[AsktiveRecord] Received question: "How many orders were placed last week?"
|
261
|
+
[AsktiveRecord] Generated SQL: SELECT COUNT(*) FROM orders WHERE created_at >= '2024-06-01' AND created_at < '2024-06-08';
|
262
|
+
[AsktiveRecord] Query results: [{"count"=>42}]
|
263
|
+
[AsktiveRecord] LLM answer: "There were 42 orders placed last week."
|
264
|
+
```
|
265
|
+
|
266
|
+
|
238
267
|
## Supported LLMs
|
239
268
|
|
240
269
|
* **Currently**: OpenAI (ChatGPT models like `gpt-3.5-turbo`, `gpt-4`).
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asktive_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- rpossan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-06-
|
11
|
+
date: 2025-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -66,20 +66,6 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '2.0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: debug
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '1.0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '1.0'
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
name: rake
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,25 +94,14 @@ dependencies:
|
|
108
94
|
- - "~>"
|
109
95
|
- !ruby/object:Gem::Version
|
110
96
|
version: '3.0'
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - "~>"
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '1.0'
|
125
|
-
description: AsktiveRecord allows developers to integrate Large Language Models (like
|
126
|
-
OpenAI's ChatGPT) into their Ruby on Rails applications, enabling natural language
|
127
|
-
querying against their database. It provides tools to configure the LLM, upload
|
128
|
-
database schema for context, and convert human-like questions into executable SQL
|
129
|
-
queries.
|
97
|
+
description: AsktiveRecord is a Ruby gem designed to bridge the gap between human
|
98
|
+
language and database queries. It lets you interact with your Rails database as
|
99
|
+
if you were having a conversation with a knowledgeable assistant. Instead of
|
100
|
+
writing SQL or chaining ActiveRecord methods, you simply ask questions in plain
|
101
|
+
English—like (or any language) 'Who are my newest users?' or 'What products sold
|
102
|
+
the most last month?' — and get clear, human-friendly answers. AsktiveRecord translates
|
103
|
+
your questions into database queries behind the scenes, so you can focus on what
|
104
|
+
you want to know, not how to write the query.
|
130
105
|
email:
|
131
106
|
- ronaldo.possan@gmail.com
|
132
107
|
executables: []
|
@@ -5700,6 +5675,5 @@ requirements: []
|
|
5700
5675
|
rubygems_version: 3.5.11
|
5701
5676
|
signing_key:
|
5702
5677
|
specification_version: 4
|
5703
|
-
summary: A Ruby gem that
|
5704
|
-
into SQL.
|
5678
|
+
summary: A Ruby gem that lets your data answer like a human
|
5705
5679
|
test_files: []
|