bx_builder_chain 0.1.4 → 0.1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9398159d26923acd8ac5f3c51675e2934dd14a89f1fd97ce088f7cd751721425
4
- data.tar.gz: 1f272643f2c6661e11a72e7221f2497cbc27a8f843b91b71a31a63df0d184e13
3
+ metadata.gz: 006f8200cd1577b6ad0687b1607cad5aabf833971d3a3e3fe2f7718988ec6fbb
4
+ data.tar.gz: 51be4ca4f480ab7ed47582fc2482b10e53e2a858eb798889ed65cbcf85f76e91
5
5
  SHA512:
6
- metadata.gz: 88d787f0ab0ff4e7a33ef5faeae4f8bb0ae18834bd3aa36fe0d82aeedee57ae9e7f6cea770915924638b08ff2c185be83fa7a132fd40f3effe602534d1528bac
7
- data.tar.gz: c943c30ea2343e02d1c7ac98ac581b5da2ad821eb33e75595bde76756b0245785f1756671be5850350126ff6fe2d3839ef66906535f2cd5fe4a42c3a7403e057
6
+ metadata.gz: 4f2e15d46fa5c06974fa10df37d27204d30bf92e4615a0c77dfbed4a0e84091a0e304ae5b98e52b2434c8937d97616e4d4e3213f959226657c84075431663b9c
7
+ data.tar.gz: b4762d1c53c6ccc6fc434f53ed058f55273798af70da586e722981a53159d49fc93f197321a7ece9b95b90c80d2c731c5de76d0830782e488571caf7cee8c682
data/README.md CHANGED
@@ -20,30 +20,57 @@ If bundler is not being used to manage dependencies, install the gem by executin
20
20
 
21
21
  $ gem install bx_builder_chain
22
22
 
23
- TODO: add rake task to create db structure
24
- ### Optional
25
23
 
26
- generate the endpoint & Active admin contollers for Builder Chain
24
+ ### Setup
27
25
 
28
- $ rails generate builder_chain:endpoints
26
+ generate the endpoints & Active admin contollers for Builder Chain along with the DB migrations
27
+
28
+ $ rails generate builder_chain:install
29
29
 
30
30
  this will add the following endpoint controllers
31
31
  - File upload
32
+ - List files
33
+ - Delete file
32
34
  - OpenAi ask / completion
33
35
  - ActiveAdmin documents controller
34
36
 
37
+ It will also add a test view / controller for testing the endpoints. ensure this is removed prior to production release
38
+
35
39
  ## Usage
36
40
  ```ruby
37
41
  require "bx_builder_chain"
38
42
  ```
39
43
 
44
+ edit the initializer config 'bx_builder_chain.rb' setup the api keys and db credentials
45
+ ```
46
+ BxBuilderChain.configure do |config|
47
+ config.openai_api_key = ENV['OPENAI_API_KEY']
48
+
49
+ # for db use this
50
+ config.pg_url = ENV['DB_URL'] || nil # eg 'postgres://postgres:password@localhost:5432/my_db'
51
+
52
+ # or this - pg_url with take preference
53
+ config.database_host = ENV['DB_HOSTNAME'] || 'localhost'
54
+ config.database_name = ENV['DB_NAME']
55
+ config.database_user = ENV['DB_USER']
56
+ config.database_password = ENV['DB_PASSWORD']
57
+ config.database_port = ENV['DB_PORT'] || '5432' # Defaulting to 5432 if not set
58
+
59
+ config.public_namespace = "public"
60
+ config.threshold = 0.25
61
+ config.default_prompt_template = "Context information is below
62
+ --------------------
63
+ %{context}
64
+ --------------------
65
+ Given the context information and not prior knowledge
66
+ answer the question: %{question}"
67
+ end
68
+ ```
69
+
40
70
  create the llm and client
41
71
  ```ruby
42
- llm = BxBuilderChain::Llm::OpenAi.new(api_key: 'open-ai-api-key')
43
72
  client = BxBuilderChain::Vectorsearch::Pgvector.new(
44
- url: 'postgres://postgres:password@localhost:5432/test', # postgres db url
45
- table_name: "embeddings", # table name for the documents to be stored
46
- llm: llm,
73
+ llm: BxBuilderChain::Llm::OpenAi.new,
47
74
  namespace: user_id # default is nil, nil is used for global public documents
48
75
  )
49
76
  ```
@@ -68,6 +95,22 @@ my_docx = "path/to/my.docx"
68
95
  client.add_data(paths: [my_pdf, my_text, my_docx])
69
96
  ```
70
97
 
98
+ Or via the service object
99
+ ```ruby
100
+ my_pdf = "path/to/my.pdf"
101
+ my_text = "path/to/my.txt"
102
+ my_docx = "path/to/my.docx"
103
+
104
+ service = DocumentUploadService.new(
105
+ files: [my_pdf, my_text, my_docx],
106
+ user_groups: current_user_document_groups, # optional defaults to ['public'] an uses the first value to store the docs
107
+ client_class_name: CLIENT_CLASS_NAME, # optional defaults to 'BxBuilderChain::Vectorsearch::Pgvector'
108
+ llm_class_name: LLM_CLASS_NAME # optional defaults to 'BxBuilderChain::Llm::OpenAi'
109
+ )
110
+
111
+ result = service.upload_and_process
112
+ ```
113
+
71
114
  Then ask the question
72
115
  ```ruby
73
116
  client.ask(question: "What is Frogger?")
@@ -39,7 +39,8 @@ module BxBuilderChain
39
39
  def self.token_limit(model_name)
40
40
  TOKEN_LIMITS[model_name]
41
41
  end
42
- def self.validate_max_tokens!(content, model_name, options = {})
42
+
43
+ def self.validate_max_tokens!(content, model_name, options = {})
43
44
  text_token_length = if content.is_a?(Array)
44
45
  content.sum { |item| token_length(item.to_json, model_name, options) }
45
46
  else
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BxBuilderChain
4
- VERSION = "0.1.4"
4
+ VERSION = "0.1.6"
5
5
  end
@@ -23,6 +23,10 @@
23
23
  height: 340px;
24
24
  }
25
25
 
26
+ div.fullwidth {
27
+ width: 100%;
28
+ }
29
+
26
30
  form {
27
31
  width: 100%;
28
32
  }
@@ -73,6 +77,19 @@
73
77
  .console_message {
74
78
  white-space: pre-line; /* To respect new lines in the content */
75
79
  }
80
+
81
+ div.fullwidth .form-group {
82
+ width: 80%;
83
+ float: left;
84
+ }
85
+
86
+ div.fullwidth .actions {
87
+ float: right;
88
+ margin-top: 17px;
89
+ }
90
+ #file_list button {
91
+ margin-left: 10px;
92
+ }
76
93
  </style>
77
94
 
78
95
  <div class="page_wrapper">
@@ -119,7 +136,24 @@
119
136
  <% end %>
120
137
  </div>
121
138
  <div style="clear: both;"></div>
139
+ <div class="form_wrapper fullwidth">
140
+ <h2>Retrieve Files</h2>
122
141
 
142
+ <%= form_tag(bx_builder_chain_documents_list_path, method: :get, id: 'list_form') do %>
143
+ <div class="form-group">
144
+ <label for="current_user_groups">Enter User ID:</label>
145
+ <%= text_field_tag 'current_user_groups', 1, class: 'form-control' %>
146
+ </div>
147
+
148
+ <div class="actions">
149
+ <%= submit_tag "Retrieve Files", class: 'btn btn-primary' %>
150
+ </div>
151
+ <% end %>
152
+
153
+ <div style="clear: both;"></div>
154
+ <ul id="file_list"></ul>
155
+ </div>
156
+ <div style="clear: both;"></div>
123
157
  <!-- Console box -->
124
158
  <div class="console_wrapper">
125
159
  <div class="console_message">
@@ -161,4 +195,83 @@
161
195
  });
162
196
  });
163
197
  });
198
+ document.addEventListener('DOMContentLoaded', function () {
199
+ const listForm = document.querySelector('#list_form');
200
+ const fileList = document.querySelector('#file_list');
201
+ const consoleBox = document.querySelector('.console_message');
202
+
203
+ listForm.addEventListener('submit', async function (event) {
204
+ event.preventDefault();
205
+
206
+ consoleBox.textContent = "Retrieving files...";
207
+ const current_user_groups = event.target.current_user_groups.value;
208
+ const endpoint = `${
209
+ event.target.action
210
+ }?current_user_groups=${current_user_groups}`;
211
+
212
+ try {
213
+ let response = await fetch(endpoint, {
214
+ method: 'GET',
215
+ headers: {
216
+ 'Content-Type': 'application/json'
217
+ }
218
+ });
219
+
220
+ if (response.ok) {
221
+ let files = await response.json();
222
+
223
+ fileList.innerHTML = ''; // Clear the file list
224
+
225
+ const current_user_groups = event.target.current_user_groups.value;
226
+ files.forEach(file => {
227
+ let listItem = document.createElement('li');
228
+ listItem.textContent = file.name; // Assuming the file object has a 'name' property
229
+
230
+ let deleteBtn = document.createElement('button');
231
+ deleteBtn.textContent = "Delete";
232
+ deleteBtn.addEventListener('click', async function () {
233
+ event.preventDefault();
234
+ await deleteFile(file.id, current_user_groups); // Assuming the file object has an 'id' property
235
+ });
236
+
237
+ listItem.appendChild(deleteBtn);
238
+ fileList.appendChild(listItem);
239
+ });
240
+
241
+ consoleBox.textContent = "Files retrieved successfully.";
242
+ } else {
243
+ let errorData = await response.json();
244
+ consoleBox.textContent = errorData.error || "An error occurred while retrieving files.";
245
+ }
246
+ } catch (error) {
247
+ consoleBox.textContent = "Failed to retrieve files. Please try again.";
248
+ }
249
+ });
250
+
251
+ async function deleteFile(fileId, current_user_groups) {
252
+ consoleBox.textContent = "Deleting file...";
253
+
254
+ try {
255
+ let response = await fetch('/bx_builder_chain/documents/delete', {
256
+ method: 'DELETE',
257
+ headers: {
258
+ 'Content-Type': 'application/json'
259
+ },
260
+ body: JSON.stringify(
261
+ {ids: [fileId], current_user_groups: current_user_groups}
262
+ )
263
+ });
264
+
265
+ if (response.ok) {
266
+ consoleBox.textContent = "File deleted successfully.";
267
+ document.querySelector('#list_form .actions input').click()
268
+ } else {
269
+ let errorData = await response.json();
270
+ consoleBox.textContent = errorData.error || "An error occurred while deleting the file.";
271
+ }
272
+ } catch (error) {
273
+ consoleBox.textContent = "Failed to delete file. Please try again.";
274
+ }
275
+ }
276
+ });
164
277
  </script>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bx_builder_chain
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Ketelle
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-02 00:00:00.000000000 Z
11
+ date: 2023-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk